顯示文章

這裡允許您檢視這個會員的所有文章。請注意, 您只能看見您有權限閱讀的文章。


文章 - stlee

頁: [1] 2 3 ... 28
1
除法在今天剛搞定...但還沒測試;不過已經能將商數的位置正確填入

不限位數的除法其實並沒比加減乘法複雜
您用一張紙和筆就能辦到了(其實程式就是將在紙上的動作搬過去)
一個除法其實也就是乘法和減法的應用(求商數用到乘法,餘數用到減法)
而乘法也有用到加法(乘積相加);所以除法也就是加減乘法的綜合運用罷了
這四個運算的概念其實您只要回想一下小學時學過的技巧便能豁然開朗
程式的訴求是[不限位數]當然不能以一般字串轉數字函數達成
而是用[字串]將其逐[位元]作運算即可,難度在於能夠[填入正確的位置]
加法的重點在於[小數點位置標齊]及進位的數字處理(加法最多只能進位1)
乘法在加法完成後幾乎也完成[因為乘法的架構和加法相同]
減法的重點除[小數點位置標齊]及借位的問題外尤其是[小數點後面的借位]也是重點
除法在上面三個模組完成後要寫的並不多(除法必須有一個[精確度]的參數)
1.除數如果有小數點則須與被除數依同右移或補0的作業
2.商數的預測,如以456除123則先取456的4除123的1可得4再以[無限位乘法]以
4*123如大於餘數則4-1再乘123直到小於餘數傳回的值就是該位數的商
3.字串前面有0必須左移(減法造成)
4.餘數長度小於除數則須補位或補0也不可忽視
5.在補位或補0時商數也必須有相對動作也是個重點
..........除法因為剛好所以還有些重點我還在註解(測試)當中所以列一些目前有遇到的
以上大概就是我寫此程式的流程...先寫加法(不困難)再寫乘法(其實跟加法差不多)
不過當初沒注意到除法也要用到乘法所以改的要死...再寫減法(跟加法差不多的概念但被借位問題困惑了一陣子).....寫完上面3個再寫除法......大概就是這樣了

好多年前的問題,最近有比較新的想法:
1.乘法就是加法的延伸,比如2*2即為把2加兩遍的意思,2*3就是把2加三遍,所以乘法函數就弄個迴路呼叫加法去算吧!
2.既然乘法是加法的延伸,那除法可不可以是減法的延伸呢?拿5來除2好了
第一次運算5-2=3商為1餘為3,餘數大於除數進入第二次運算
第二次運算3-2=1商加1(=2)餘為1,餘數小於除數停止運算
每減一次(運算一次減法)商數就加1,判斷餘數比除數大時就進入下一次運算並用現在的餘數去減除數直到餘數小於除數,不過還是必須先補位&補0
哈哈,還是兜回建構式數學了^_^

2
我另一台的java就是升級以後不能使用的,後來想乾脆找另一個網站還比較快

果然找到群益證的flash版線圖還比較好用(因為現在pc home的java版線圖還有中文編碼的問題)

不過技術線圖這種東西要完全稿懂可能要先花個幾百萬的學費去實踐然後要到專家程度再花個幾千萬丟到股市去實踐吧

其實股市就是個買賣關係的問題,輸贏全在<心法>至於所謂心法有人說是經驗也有人說是自己的賺錢模式~~~離題了@_@

3
在pc home股市的個股技術分析圖如果有跟我一樣看不到而且浏覽器剛好是goog chrom
雖然照指示安裝[最新版]java不過卻還是没辦法看到那該死的技術分析圖可以試試以下方法

1.點進無法顯示的圖下面有java下載的連结-->若你無法看到xxxx請先下載java軟體

2.進入java下載中心後到Linux區下載一個java壓縮檔到/home/xxxx裡面
   我下載的是 /home/stlee/jre-7u9-linux-i586.tar.gz

3.不太會解壓的請在Linux下載區那裡點一個<指示>的分頁出來在<2.安裝>的步骤<3.解壓縮 tarball 並安裝 Java >有解壓指令
  要注意該指令中的版本號與下載來的可能有一點點不同:
  指示的指令
   tar zxvf jre-7u7-linux-i586.tar.gz
  我下載的是
   jre-7u9-linux-i586.tar.gz
   所以複制到终端機執解壓時將7u7改成7u9就可以了
  解壓成功後在/home/stlee內會有一個jre1.7.0_09的目錄

4.<3.啟用與設定>雖然寫的是Firefox 或 Mozilla的解决方法不過卻指出一條路就是這一段
  建立符號連結至 libnpjp2.so 檔案 (位於瀏覽器外掛程式目錄中)
  * 請移至 Firefox 安裝目錄下的 plugins 子目錄
    cd <Firefox 安裝目錄>/plugins
  * 建立符號連結
    ln -s <Java 安裝目錄>/lib/i386/libnpjp2.so


5.是滴!!我們要做的就是
   cd /opt/google/chrome/plugins
  移到這個目錄下(或可先用檔案總管搜尋chrome)然後建立(重建)一個符號連結
    ln -s /home/stlee/jre1.7.0_09/lib/i386/libnpjp2.so
   不過如果libnpjp2.so本來就存在,用一般權限是殺不死它的,用下面指令殺吧
   sudo -s
   rm libnpjp2.so
   這時將libnpjp2.so重指到/home/stlee/........红色的libnpjp2.so就變成可以可連結的藍色了(终端機下ls指令時)

6.重開一個浏覽器然後執行需要java的頁面會問你每次都要執行或只有這一次這就看個人需求了


ps.我的情形是(個人猜想,没時間証實)java的安装,符號連結指向root那裡去了所以用一般登入時就不能使用java了


11/09日補充:

今天在另一台以此法實作發現在步驟5有個小問題
/opt/google/chrome下面沒有plugins這一個目錄(這一定是幻覺~_~)
既然沒有plugins那就自己做一個出來吧
  sudo -s
  mkdir plugins
然後一樣進入新做的plugins目錄後建立(重建)一個符號連結
  ln -s /home/stlee/jre1.7.0_09/lib/i386/libnpjp2.so
很好!!!我好多年沒在這一台pc上看到技術線型了,今天終於又重見了(拉炮)

4
要能顯示UTF-8還要K一下這一篇
http://phorum.study-area.org/index.php/topic,52642.msg269309.html#msg269309

然後參考一下這一篇
http://phorum.study-area.org/index.php/topic,48642.msg246480.html#msg246480
不過很可惜的因為時間有點久遠所以圖片(程式最終的效果圖)都看不到了

反正要處理的就是
1.鍵盤(單鍵及複合鍵)
2.螢幕(顏色及視窗,沒錯!文字模式下也有視窗可以玩,說穿了就是怎麼蓋上去及蓋上去的怎麼還原回去)
3.檔案(I/O)

5
雜七雜八 / Re: 剛剛接到詐騙電話
« 於: 2012-07-31 01:05 »
補充一下
第一個來電是冒充購物站的工作人員
通話時聲音會有點忽大忽小,還斷線一次
對方能說出正確購物日期、消費金額跟購買的東西
老實說,這第一通電話我是有上釣了 :P
第二通『銀行』來電通話品質一樣很差
聽到奇怪口音心裡就有點懷疑
還要我到提款機查餘額印出來
並等他電話....^_^

上次一個問我餘額
我回他有十億(這當然是唬爛的)然後接著跟他說:你有需要我可以燒給你不用轉帳了(掛電話並關機)
 :D :D :D

6
在這麼無成交量下進出頻繁,那些個營業員們一定愛死你了
基本上台灣股市要有日均量1000e才能算是多頭的攻擊量
新手看價,老手看量,高手看勢

要從股市領薪水.......一個大家都知道的二八法則(玩股票不要說不知道二八法則)
也就是說如果勝率只有20%而失敗率卻有80%的話
那去簽職棒吧~~~~~勝率一定是50%的

如果一定要投資的話(長期)試試往東協的方向思考思考
而東協一定與中國大陸的發展脫不了干系
大陸的人口紅利光環漸漸消退中
有人消退就會有人崛起~~東協應該會不錯唷

7
不是還有南科跟華亞科的嘛
台塑集團現在不只是洗頭,可以說整顆頭都泡下去了~~沒辦法!誰叫他們太有肉了

應該還不用擔心玩蛋依媽思去了~~~
阿本仔不舉,台灣跟著陽痿?!還不至於吧...阿本仔不舉好多年了咧-..-

反而當奇美電這隻大象腳步踉蹌時就有禿鷹盤旋等著撿骨
可是怎麼這隻禿鷹比大象還大隻呀~~這個世道真的變了

所以這種叢林法則的戲碼上演時~搬沙發看戲...oh ya

8
有沒有核試除了輻射物質的觀測還有電磁脈衝波吧!?
http://zh.wikipedia.org/wiki/%E7%94%B5%E7%A3%81%E8%84%89%E5%86%B2
而且就算真的核試了,以現在衛星科技的發達會沒有人(國家)發現
如果現在真能做到進行核試而不被人發現(除了被文章作者發現)
那麼阿本仔已經有本錢跟老美大小聲了 ;D




10
字串搜尋喔!我寫過一個跟您的不太一樣咧,要不要參考一下呀!
http://phorum.study-area.org/index.php/topic,61407.msg311392.html#msg311392
大概在中間部份有一個lee_memchunt()函數

全文字串搜尋要注意"不要一段一段找"而是要"一個字元一個字元找"而且又要有效率的找
因為比如要在"124312141231234123134"裏面找出1234就不能4個字元為一段的找
可是在每個字元都往後找4個Byte又沒效率.....其他重點不多說了,函數裏面有註解囉

11
肉腳版 / 回覆: 麗山經典程設的幾個題目
« 於: 2010-12-06 12:08 »
樓上用JS的比較符合提問者的程式邏輯(從後面乘回來)
而我在書上抄的公式是從前面乘

不過身份字號中的10+1位數(英文字被拆成2位數)只要其中一位數相加後的結果是10
那不管其他位數怎麼相加乘就一定能被10整除

以我的來說D120xxxx39第一個位數的D用我那個公式代換後不管怎麼算一定被10整除
因為D=13而1+9=10所以不管後面怎麼算都正確

只是不知道比如S=26的高雄縣用哪一個公式算會正確呢?

12
肉腳版 / 回覆: 麗山經典程設的幾個題目
« 於: 2010-12-06 00:40 »
身分證認證 ....這是俺考丙級之末代BASIC時術科其中一題呀 ;D(現在丙級很像考VB,我那時還沒有乙級可以考,現在很像有乙級考了是考C的)

英文字部份令其為X1,X2其X1為十位數X2為個位數
也就是比如身份證號的第一個英文字母為E則查表後E=14將之拆出X1=1,X2=4

而英文字後面的九位數字部份令其為D1~D9
整個的計算公式為
Y=(X1+9) * (X2+8) * (D1+7) * (D2+6) * (D3+5) * (D4+4) * (D5+3) * (D6+2) * (D7+D8+D9)
以上是我印象中的公式,為什麼說是印象中呢,因為書上的有點不一樣(我那本術科的書還在咧!不然怎麼答這一題呀)
書上的是這樣的:
Y=X1+9 * X2+8 * D1+7 * D2+6 * D3+5 * D4+4 * D5+3 * D6+2 * D7+D8+D9
可能BASIC先乘除後加減順序不太一樣或書上的排版錯誤(還是我記錯了),反正您都試試看,因為我考完就忘了-_-

然後Y能被10整除則此身份證號碼正確
性別判斷:D1只可為1或2,1表男性2表女性

ps.
應該是我印象中的那一個比較正確,因為我試算自己的身份證號時發現數字部份其中有一個0所以加上()該算式才有意義
否則算到0那裡就都歸零了(任何數乘0皆為0)基本上該算式就變得沒有意義了


13
封包喔!我以前也寫過一個耶
不過寫的是我的linux pc向比如yahoo的伺服器要求頁面的詢答,不知道是不是您要的?
http://phorum.study-area.org/index.php/topic,61407.msg311354.html#msg311354

14
C/C++程式設計討論區 / 回覆: c的遞回問題
« 於: 2010-12-02 23:14 »
加上else當然不會讓你想要的結果出現=..="

只是else if()後面要接上else......現在都不這樣寫了乎?

如果真的不需要那個else最少也給他個空敘述
比如
代碼: [選擇]
else
{;}
不過有時候發生想像不到的狀況就是會出現在else裏面
所以我都會讓他顯示一個無意義的訊息出來
比如
代碼: [選擇]
else
  printf("12345679801234657890\n");
這樣當出現這個無意義的訊息時我就知道例外狀況發生了
這種除錯即在程式裡的寫法總比您這樣完全沒有觀測及除錯的code就能把程式寫完的神人寫法
說實在!小弟不會咧@@!

15
C/C++程式設計討論區 / 回覆: c的遞回問題
« 於: 2010-12-02 09:38 »
代碼: [選擇]
void edge1(int p1, int dist, int pos)
{
  int i;
  if (dist == 2)
  {
    path[pos].p1 = p1%12;
    path[pos].p2 = (p1+1)%12;
    if (pos == items-1) printPath();
  }
  else if (dist > 2)
  {
    int step;
    for (step = 2; step < dist; step += 2)
    {
  edge1( p1, step, pos ); 
  edge1( p1+step, dist-step, pos + (step >> 1) );
    }
    path[pos].p1 = p1%12;
    path[pos].p2 = (p1+dist-1)%12;
    edge1( p1+1, dist-2, pos+1 );
  }
}
else//else if後面怎麼沒else?
{
printf("其他狀況在這裡發生......比如dist<2...\n");
}

16
C/C++程式設計討論區 / 回覆: c的遞回問題
« 於: 2010-12-02 00:12 »
您不覺得edge1()函數裏面少了什麼嗎?

17
C/C++程式設計討論區 / 回覆: c的遞回問題
« 於: 2010-12-01 00:23 »
說指導不敢當,大家研究一下^_^
有問題的應該是void edge1(int p1, int dist, int pos)這個函數沒錯吧?

寫作遞迴有個很重要的觀念就是--->有進有出
意思就是說安排遞迴的入口(呼叫自己)時千萬記得安排出口

而edge1()這個函數的出口在哪裡呢?再檢視一下!!
代碼: [選擇]
void edge1(int p1, int dist, int pos)
{
  int i;
  if (dist == 2)
  {
    path[pos].p1 = p1%12;
    path[pos].p2 = (p1+1)%12;
    if (pos == items-1) printPath();
  }
  else if (dist > 2)
  {
    int step;
    for (step = 2; step < dist; step += 2)
    {
  edge1( p1, step, pos );  
  edge1( p1+step, dist-step, pos + (step >> 1) );
    }
    path[pos].p1 = p1%12;
    path[pos].p2 = (p1+dist-1)%12;
    edge1( p1+1, dist-2, pos+1 );
  }
}

當dist==2時
代碼: [選擇]
if (dist == 2)
  {
    path[pos].p1 = p1%12;
    path[pos].p2 = (p1+1)%12;
    if (pos == items-1) printPath();
  }
這裡形成一個出口,沒問題
不過建議最好還是寫個return啦!應該沒差這一行吧?

而遞迴入口則在else if (dist > 2) 裡的最後面遇到
代碼: [選擇]
edge1( p1+1, dist-2, pos+1 );
所以這裡在dist==4的時候就沒了,不會有機會遇到dist>4以上
因為你減的是2而出口
代碼: [選擇]
if (dist == 2)
{
...
}
當然dist==4時遞迴就結束啦

而迴路裏面的條件
代碼: [選擇]
for (step = 2; step < dist; step += 2)
基本上也不會有機會遇到dist>4了

簡單講這個遞迴並沒有實際展開~~~
要不然就是dist傳入4以上時就會形成無窮迴路

19
另外就是多看其他類型的書,可以旁徵博引,最近剛好有一篇 必看!IT好書101

31.C名題精選百則-使用C語言-技巧篇
冼鏡光著->冼的音同省.前陣子從yahoo的新聞(台灣的怪姓)裡才知道這個字的正確讀法
這本我有 ;D
從本書得到的啟發多於從書中找到的答案
而且很像所推荐的C語言類,這本是唯一一本中文的(非翻譯)

函數庫的書也要買一本,因為從中找到的答案會比啟發多 :P




20
我想寫一個做一個程式~ 拜託大大幫忙 ><~   突然間要交 真的很趕  ???

有趕羚羊那麼趕嗎??

21
我想請問有人曾經利用socket傳送指標陣列嗎?

A int array1[]={1,2,3,4};
B int *array2=malloc(16);
我可以確定利用socket傳送A可以成功,但是傳送B這種可以嗎?

當然可以呀!為何不行呢?
http://phorum.study-area.org/index.php/topic,61407.msg311354.html#msg311354

不過您所謂的"指標陣列"是指[一個指向陣列的指標]還是[存放著很多個指標的陣列]?


22
如果不要燈光美氣氛佳的餐廳

那麼公園南路一直走過太子龍到海安路左轉(就5678叉路那裡左轉進海安路)

從那裡開始一直到夏林路水萍塭公園也是有不少小炒海鮮豬牛羊肉爐

[瑞穗]豬,牛肉爐一定要試試(就左轉過去後約300公尺,左手邊)

地圖(最後面兩個)
http://maps.google.com.tw/maps/ms?hl=zh-TW&ie=UTF8&msa=0&msid=101651413991430101656.00044bb6301a9e03936f6&brcurrent=3,0x346dd8a633589bdf:0x21b05a854570e966,0&t=h&z=13


23
再來呢!是一些需要自行計算的替換,比如字串長度例如POST封包\r\n\r\n後面要帶多少Byte必須在表頭裏面告訴伺服器的
代碼: [選擇]
/*特殊的替換:Content-Length標頭是\r\n\r\n後的字串長度所以必須等全替換完再來計算*/
  if(code & CONTLEN)
  {
    tmp=lee_rtvmem2sl(sendtmp,0,sendtmpsz,"\r\n\r\n","\n",RETRB|RETSLEN,&tmpsz);
    sendtmp=lee_memcrepa(sendtmp,&sendtmpsz,"[>cont_len<]",tmp);
    free(tmp);
  }
還有時間
代碼: [選擇]
/*特殊的替換: 時間字串*/
  if(code & SYSTIME)
  {     
    sys_time=lee_timestr(addsec,0);
    sendtmp=lee_memcrepa(sendtmp,&sendtmpsz,"[>sys_time<]",sys_time);
    free(sys_time);
  }


我最多只要加一分鐘....XDDD

char *lee_timestr(int addsec,int code)
{
  char *sys_time;
  char *timeform[]={"%a, %d %b %Y %H:%M:%S GMT",//Sun, 23 May 2010 07:55:36 GMT
                    "%D %r",// 05/23/10 08:10:14 AM
                    NULL};
  time_t clock;
  struct tm *tm;
  int s,m,h;

  if(code<0)
    code=0;

  sys_time=calloc(sizeof(char),128);

  /*製作時間字串*/
  time(&clock);
  tm=gmtime(&clock);
  if(addsec>0)
  {
    s=tm->tm_sec;//秒
    m=tm->tm_min;//分
    h=tm->tm_hour;//時/24
    s+=addsec;
    if(s>=60)
    {
      s-=60;
      m+=1;
    }
    if(m>=60)
    {
      m-=60;
      h+=1;
    }
    if(h>=24)
      h-=24;
    tm->tm_sec=s;
    tm->tm_min=m;
    tm->tm_hour=h;
  }
  strftime(sys_time,128,timeform[code],tm);
  return(sys_time);
}

這些呢用一個窗口函數包起來,然後以一個int code來加以控制,以一個int控制(傳入)多個動作(參數)以前討論過了
http://phorum.study-area.org/index.php/topic,51286.msg261980.html#msg261980

然後我們的封包大概長這樣,就可以把時間字串或每次都不一定會相同的字串長度字串視為一個變數以標籤替換之即可
代碼: [選擇]
If-Modified-Since: [>sys_time<]
Content-Length: [>cont_len<]
.........................[/code]

24
好了!基本的東西大概就只差一樣了,就是我們要發出去的封包並不是與抓下來的封包一模一樣的
不過也差不了多遠,只要把該頁多抓個幾次互相比對以後大概就知道哪些是可以照抄哪些是需要替換的了
最簡單的講法就是日期了,總不能您發過去的封包每一次都是那個抓下來的日期吧

那麼現在問題來了......問題在哪裡?......當然是怎麼個換法呀@@!
弄個標籤如何,也就是說弄一個像[stp-1]這樣一種的標籤,然後讓程式找到特定標籤後予以替換
代碼: [選擇]
/*將mem內所有的oris字串替換成reps字串
tmp=lee_memcrepa(tmp,&tmpsz,"<~username~>",username);
tmp自己是參數同時也是傳回空間的接收體,因為本函數會變更tmpsz
以及釋放原tmp所指空間而以函數內宣告的空間傳回去所以必須讓空間指標自己替換自己
這樣一來在呼叫者函數不用宣告多個空間指標來存放每一次的替換結果或交互free()掉上一次替換結果
因為要的是替換後的結果,而被替換前的空間都會在替換完後馬上被free掉
*/
char *lee_memcrepa(char *mem,int *memsz,char *oris,char *reps)
{
  int repfoot,i,n,k,osn,rsn,newsz;
  char *tmp;

  newsz=*memsz;
  tmp=malloc(newsz * sizeof(char));
  repfoot=lee_memchunt(mem,oris,0,*memsz,FROM);
  if(repfoot==-1)
  {
    *memsz=newsz;
    return(mem);
  }
  osn=strlen(oris);
  rsn=strlen(reps);

/*printf("repfoot=%d oris=%s reps=%s newsz=%d *memsz=%d \n",
          repfoot,oris,reps,newsz,*memsz);
getchar();
/**/
  for(i=0,n=0;i < *memsz;i++,n++)
  {
    if(i==repfoot)
    {
      i+=osn;//將複製旗標加上被替換字串長度相當於忽略被替換字串
      repfoot=lee_memchunt(mem,oris,i,*memsz,FROM);//從被忽略處再找下一個oris字串
      /*當被替換字串長度比替換字串長度短時rsn-osn會得出正值,反之會得到負值
        在其後再加以判斷,如原空間不足則重宣告(加大)空間,而原空間長度足夠裝下替換後的長度
        則只需要控制newsz即可達到要求,不需重新宣告空間*/
      newsz+=rsn-osn;
      if(osn<rsn)//當伺服器傳來的uid字串會比自定義的替換識別字串來得長時需重宣告(加大)空間
        tmp=realloc(tmp,newsz * sizeof(char));
      for(k=0;k<rsn;k++,n++)//替換字串複製到新的空間
        *(tmp+n)=*(reps+k);

    }
    *(tmp+n)=*(mem+i);
  }
  free(mem);
  *memsz=newsz;
  return(&*tmp);
}

如果有很多個要替換咧?
當然是弄個二維陣列然後以迴路跑一趟嚕
代碼: [選擇]
..........................................................................................
範例:在程式內宣告好的字串陣列
char string[STRN][9]={"ARC","ARKW","SASECFKW","ENDRKW"};
char **sp;

gplkwp=lee_mem2sp((char *)string,sizeof(string));string需做轉型否則會有warning(警告)產生
for(i=0;i<nstrn;i++)
  printf("string[%d]=%s",i,*(sp+i));

...........................................................................................

char **lee_mem2sp(char *mem,int size)
{

  char **sp;
  int n,x;
  sp=lee_mem2spn(mem,size,&n,&x);
  return(sp);
}


char **lee_mem2spn(char *mem,int size,int *strn,int *maxlen)
{

  char **sp;
  int i,n,x;
  if(size<1)
  {
    sp=malloc( 1 * sizeof(char *));
    *(sp+0)=&*(mem+0);
    *strn=0;
    *maxlen=0;
    return(sp);
  }


  *strn=lee_memcstrn(mem,size);/*先計算*mem共有幾列資料或有幾個元素*/
  sp=malloc( *strn * sizeof(char *));
  *maxlen=0;
  /*以下迴路的邏輯與lee_memcstrn()相同*/
  for(i=0,n=0;i < size ;i++)
  {
    if(*(mem+i)!='\0' && *(mem+i)!='\n')/*略過資料列之間連續的'\0'或'\n*/
    {
      *(sp+n)=&*(mem+i);
      n+=1;
      x=0;
      while(i < size)/*此迴路讓i略過本列資料到達本列的'\0'或'\n以開始找下列資料旗標所在*/
      {
        if(*(mem+i)=='\0' || *(mem+i)=='\n')
          break;
        i+=1;
        x+=1;
      }
      if(*maxlen<x)
        *maxlen=x;
    }
  }
  return(sp);
}

/*計算記憶體區塊內有幾列有效的資料(共有幾個元素是以'\0'或'\n'分隔開的)
可略過連續的'\0'或'\n'

char *mem 存放所有資料的記憶體空間,就是從此空間擷取所需資料
int ssz 記憶體空間*s的長度
*/
int lee_memcstrn(char *mem,int size)
{
  int i,strn;
  /*本迴路是已經假設各列資料間有可能為了排列美觀而在各列資料間有換列號'\n'字元的想法寫成
  因為*s除了有可能是一個已擷取好的不定寬度二維字串陣列外也有可能是一個剛從檔案映射的記
  體區塊,這種映射檔案的記憶體區塊大多有連續換行號的情形存在,而固定寬度的二維字串陣列在各
  元素間更充斥'\0'字元(有初始化過的)*/
  for(i=0,strn=0;i<size;i++)
  {
    if(*(mem+i)!='\0' && *(mem+i)!='\n')/*略過資料列之間連續的'\0'或'\n*/
    {
      strn+=1;
      while(i<size)/*此迴路讓i略過本列資料到達本列的'\0'或'\n以開始找下列資料旗標所在*/
      {
        if(*(mem+i)=='\0' || *(mem+i)=='\n')
          break;
        i+=1;
      }
    }
  }
  return(strn);
}


然後第1種使用方法就是宣告一個陣列,定位後跑個迴路,不過這並不適用在一問一答的狀況下
而是在某頁中有陣列需要讀取然後整批的在下一次的GET或POST中將這些陣列裡的資料代進去
代碼: [選擇]
char betfkw[20][41]={"xxx","xxx",
        "active\" value=\"","type\" value=\""};

sp=lee_mem2spn((char *)betfkw,sizeof(betfkw),&spn,&x);
for(i=0;i<spn;i++)
{
  tmp=lee_rtvmem2sl(*recvtmp,0,*recvtmpsz,*(sp+i),"\"",RETRB,&n);
  memset(renums,'\0',11);
  snprintf(renums,11,"[>%d<]",i);
  sendtmp=lee_memcrepa(sendtmp,&sendtmpsz,renums,tmp);
  free(tmp);
}
這裡注意一下,如果要擷取的字串內含有"或'字元則在前面加一個\字元
至於為什麼,您在vi裏面敲進去就能了解了

上面說的是陣列的方法,那在一問一答時有的會在某頁裡夾個uid或cookie然後其下數頁都要帶著這個字串咧
比如這一種的封包
代碼: [選擇]
GET /aaa/xxx.php?uid=3cf216db5f9b24b2 HTTP/1.1
Accept: */*
Accept-Language: zh-tw
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.4; InfoPath.1)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

那他前面(或更前面)一定有一個封包是帶著這一個uid字串的,所以......
前面不是有個lee_rtvmem2sl()函數嗎!?這個函數專門幹這件事情的啦 ;)
然後搭配lee_memcrepa()就可以了
如果要從頭帶到尾,且中間常常加進比如gid啦type啦code呀......
代碼: [選擇]
main()
{
  char **orikw,**retkw;
  int orisn,retsn;

  orikw=lee_memsspins(-1,"[>username<]",1,INSERT,orikw,&orisn);
  retkw=lee_memsspins(-1,username,1,INSERT,retkw,&retsn);
  orikw=lee_memsspins(orisn,"[>passwd<]",1,INSERT,orikw,&orisn);
  retkw=lee_memsspins(retsn,passwd,1,INSERT,retkw,&retsn);

  go(&orikw,&orisn,&retkw,&retsn);
}

int go(char ***orikw,int *orisn,
       char ***retkw,int *retsn)
{
  int i;

  /*將封包字串內需要替換的部份全部換起來*/
  for(i=0;i<*orisn;i++)
    sendtmp=lee_memcrepa(sendtmp,&sendtmpsz,*(*(orikw)+i),*(*(retkw)+i));
}

二維字串陣列指標插入
代碼: [選擇]
/*二維字串指標陣列行插入(會產生一個字串實體空間及一個指向該空間的二維指標)
在*sp的第flag處插入insnum個insstr字串(依模式code可以不理會或補足,補到尾端)
*/
char **lee_memsspins(int flag,char *insstr,int insnum,int code,
                     char **sp,int *strn)
{
  char **nsp,**stp;
  int i,n,k,x,inn,size;

  if(*strn<1 || flag<0)//**sp未初始化(**sp無指向內容)
  {
    nsp=lee_memcp2spn(insstr,strlen(insstr),&*strn,&i);
    return(nsp);
  }

  if(code==CPMTTY)/*補足到flag*/
  {
    if(*strn>flag)/*元素數量已大於插入點不用補*/
      return(sp);
    else
      inn=flag - *strn + insnum;
  }
  else if(code==IGNORE)/*不足不理會*/
  {
    if(*strn>flag)/*元素數量大於插入點需插入*/
      inn=insnum;
    else
      return(sp);
  }
  else if(code==INSERT)/*插入*/
  {
    if(*strn<=flag)/*插入點在尾端之後效果同CPMTTY(補足)*/
      inn=flag - *strn + insnum;
    else
      inn=insnum;
  }
  else/*ENDMOS不足的補尾端或從插入點補入   ALLMOS全部補尾端*/
  {
    if(*strn<=flag)
      flag+=insnum-1;
    inn=insnum;
  }
  stp=lee_memns2sp(insstr,inn);
  /*宣告重新定址的指標空間*/
  nsp=malloc((*strn + inn) * sizeof(char *));

/*lee_wmucls(stdscr,0,27,90,30,B0F7,1);
for(i=0;i<inn;i++)
  mvprintw(28,i*7,"%s",*(stp+i));
mvprintw(29,0,"flag=%d insstr=%s *strn=%d insnum=%d inn=%d ",flag,insstr,*strn,insnum,inn);
refresh();
/**/

  if(*strn<flag || code==ALLMOS)
  {
    for(i=0;i<*strn;i++)
      *(nsp+i)=*(sp+i);
    for(i=*strn,n=0;n<inn;i++,n++)
      *(nsp+i)=*(stp+n);
  }
  else
  {
    for(i=0,x=0;i<*strn+inn;i++)
    {
      if(i==flag)
      {
        for(k=i,n=0;n<inn;k++,n++)
          *(nsp+k)=*(stp+n);
        i=k-1;
      }
      else
      {
        *(nsp+i)=*(sp+x);
        x+=1;
      }
    }
  }
  free(stp);/*stp所指內容已被*nsp複製(只複製位址)故本二維指標陣列已無用需予釋放*/
  free(sp);
  *strn+=inn;
  return(nsp);
}

/*宣告strn個以'\0'結尾的str字串後定址傳回一個二維指標陣列
*/
char **lee_memns2sp(char *str,int strn)
{
  char **sp,*tmp;
  int i,len;

  len=strlen(str);
  if(strn<=0 || len<=0)
  {
    sp=(char **)malloc( 1 * sizeof(char **));
    sp=NULL;
    return(sp);
  }
  sp=(char **)malloc(strn * sizeof(char **));
  for(i=0;i<strn;i++)
  {
    tmp=(char *)malloc( len * sizeof(char) + 1);
    strcpy(tmp,str);
    *(tmp+len)='\0';
    *(sp+i)=tmp;
  }
  return(sp);
}

然後我們檔案裡的封包就可以存成這樣來替換每一次登入網頁所需要的各項"變數"了
代碼: [選擇]
[betpost]
POST /aaa/xxx.php HTTP/1.1^M
Referer: http://999.com/aaa/xxx.php?gid=[>gid<]&type=[>type<]&uid=[>login_uid<]^M
Accept-Language: zh-tw^M
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0)^M
Content-Type: application/x-www-form-urlencoded^M
Content-Length: [>contlen<]^M
^M
uid=[>login_uid<]&active=[>1<]&type=[>2<]&gid=[>gid<]&num=[>num<]&con=[>3<]&io=[>4<]&max=[>5<]&min=[>6<]&sing=[>6<]&reing=[>7<]&pt=[>8<]
[/betpost]

如此一來自動化網頁登入是不是給他變得彷彿有點輕鬆了呢!?
不過事情都不是想像那麼簡單的~~~~~不過基本上大概就是這樣而已了


25
比較理想的狀況是我們把封包抓下來存成文字檔以後經由程式讀取該文字檔內容
自動分析後執行相同的動作,當然...這已經不是理想狀況,而是--->你.作.夢 ;D

那好吧,退而求其次,把該文字檔稍微調整調整呢!
嗯....這就是我現在正在做的事情了
比如進入某網站後會有一些圖片連結,或是文字連結,點取這些連結後又進入另一頁面
或輸入某些資料就進入正式頁面..........

其實如果您仔細看Wireshark所擷取的封包(過濾出只有HTTP的封包)後您會發現
大部份都是符合一種一問一答的狀況的,也就是在一個GET或POST後面才會有個HTTP
如果其中您拿掉嵌入在裏面的java或其他代碼(也就是大家都看不懂的英文)後發現
這些個HTTP後面跟著的某些您能看得懂的中文不就是某些頁面的文字嗎?
所以HTTP就是伺服器[答]回來的封包,而GET或POST就是我們要[問]過去的啦!

那麼簡單的說把Wireshark抓到的關於GET以及POST的部份封包照抄發回去就是很完美的自動化上網程式乎!
嗯...這個....看下去您就知道困難點在哪裡了
首先一個口令一個動作是我們要求程式能充份摹仿我們的封包,但卻又不能一模一樣,而是要求能唯妙唯肖
所以首先我們必須把這些EGT與POST的封包存在一起然後能有個函數能讀取我們所指定的動作
就像這個樣子
代碼: [選擇]
[stp-1]
.....
.....
[/stp-1]
[stp-2]
.....
.....
[/stp-2]
[stp-3]
.....
.....
[/stp-3]


讀檔應該不困難所以不囉唆,至於字串擷取函數這裡貢獻一個參考參考
代碼: [選擇]
/*003-1在一記憶體區塊內擷取*fkw與*ekw的相關字串(不會消除'\0')
*/
char *lee_rtvmem2sl(char *mem,int foot,int end,char *fkw,char *ekw,int code,int *getsize)
{
  char *tmp,*lenstr;
  int fslen,eslen,fp,ep,sn;
  int i,n,f,e;

  if(fkw=='\0')
    fslen=1;
  else
    fslen=strlen(fkw);

  if(ekw=='\0')
    eslen=1;
  else
    eslen=strlen(ekw);

  f=lee_memchunt(mem,fkw,foot,end,FROM);
  if(f>=0)
    e=lee_memchunt(mem,ekw,f+fslen,end,FROM);
  if(f==-1 || e==-1 || e-f==1 )/*搜尋(起,終)的識別字在*s裡面找不到*/
  {
    tmp=malloc(1);
    *(tmp+0)='\0';
    *getsize=0;
    return(tmp);
  }

  /*依code模式設定foot與end值讓以下迴路進行複製*/
  lee_rtvcodeset(code,&fp,&ep,e,fslen,eslen,f,e);
  /*要傳回以指定方式擷取出字串的char型別的字串長度
  在code參數加上此選項相當於在呼叫者函數內的strnprintf()搬進此函數內
  使用方法比如取身+尾則code傳入 RETRBR | RETSLEN 即可取得所擷取長度的char型態字串
  而不是所擷取出來的字串*/
  if(code & RETSLEN)
  {
    sn=ep-fp;//RETRB只取身時的sn是不含'\0'及頭or尾的實際長度
    lenstr=calloc( sizeof(char),21);
    snprintf(lenstr,21,"%d",sn);
    *getsize=strlen(lenstr);
    return(lenstr);
  }
  else/*傳回指定方式所擷取的字串*/
  {
  /*mem最後一個字元本身是字串結束的'\0'時不必多加一個'\0'給擷取出的字串*/
    if(*(mem+(ep-1)) == '\0')
      sn=ep-fp;
    else
      sn=ep-fp+1;
    tmp=malloc(sn * sizeof(char));
    for(i=fp,n=0; n<sn ;i++,n++)/*複製*/
      *(tmp+n)=*(mem+i);
    *(tmp+sn-1)='\0';
    *getsize=sn;
    return(tmp);
  }
}
lee_rtvmem2sl()擷取模式的設定
代碼: [選擇]
/*001字串擷取函數擷取模式的設定,主要依code決定要將*foot與*end設定為何值
int sslen 此值需傳入以strlen()算出來的值不可傳入總size值
*/
void lee_rtvcodeset(int code,int *foot,int *end,
                    int sslen,int fslen,int eslen,int f,int e)
{

  if( code & RETRB )/*只取身*/
  {
    *foot=fslen+f;
    *end=e;
  }
  else if( code & RETRF )/*只取頭前*/
  {
    *foot=0;
    *end=f;
  }
  else if( code & RETRE )/*只取尾後*/
  {
    *foot=eslen+f;
    *end=sslen;
  }
  else if( code & RETRHB )/*頭+身*/
  {
    *foot=f;
    *end=e;
  }
  else if( code & RETRBR )/*身+尾*/
  {
    *foot=fslen+f;
    *end=eslen+e;
  }
  else if( code & RETRHF )/*頭+頭前*/
  {
    *foot=0;
    *end=f+fslen;
  }
  else if( code & RETRRE )/*尾+尾後*/
  {
    *foot=e;
    *end=sslen;
  }

  else if( code & RETRHBR )/*頭+身+尾*/
  {
    *foot=f;
    *end=eslen+e;
  }
  else
  {
    *foot=0;
    *end=0;
  }
}

會一直被用到的字串搜尋函數
代碼: [選擇]
/*在一記憶體*mem內搜尋字串*hstr從footp找到endp,參數dir控制:往前(逆)INFO 往後(順)FROM 向搜尋
以strstr()也可找子字串但會受限於 '\0' 字串結束字元,
本函數不會受'\0'限制所以可搜尋2,3維陣列的全文搜尋,但要注意foot~endp的範圍不可超
過*mem實際宣告的大小即當mem[10][18]時endp不可大於10*18
*hstr必需是以'\0'結尾的字串

傳回的是旗標值,即mem[n]的索引n值,如果是二維陣列以下方式可求得

 char mem[sy[sx];
 int hun,x,y,max;
 
 max=sy*sx;
 hun=lee_memchunt(mem,hstr,0,max,FROM);
 ans=div(hun,sx);          ~~~~~起點,終點可以從指定段落開始(不是0及max)
 y=ans.quot;                    但終點不可超出max
 x=ans.rem;
 strncat(s,mem+(y*sy)+x,strlen(hstr));
           ~~~~~~~~~~~~
細微差別:不論順向或逆向起點及終點在呼叫者函數皆不用傳入游標所在旗標+1或-1這是因為:
逆向時第一層迴路起始是i=endp-1而第二層迴路是k=i+1(單一字元及游標本身在待尋字串內可正確)
順向時第一層迴路起始是i=footp而第二層迴路是k=i+1(游標在待尋字串左邊1個位元可正確)
*/
int lee_memchunt(char *mem,char *kws,int footp,int endp,int dir)
{
  int kwsn,i,n,k,x;

  if(endp<1 || footp<0)/*無法搜尋的參數*/
    return(-1);

  if(*kws=='\n' || *kws=='\0')/*待搜尋字串*kws本身是換行'\n'或字串結束'\0'字元*/
  {
    for(i=footp;i<endp;i++)
      if(*(mem+i)=='\0' || *(mem+i)=='\n')
        return(i);/*footp~endp中間有'\0'或'\n'*/
    return(endp);/*footp~endp中間沒有'\0'或'\n'*/
  }

  kwsn=strlen(kws);
  if(dir==INFO)/*往前(逆向)搜尋,INFO*/
  {
    x=0;
    for(i=endp-1;i>=footp;i--)/*因傳回k+1所以從endp-1找到footp*/
    {
      if(*(mem+i) == *(kws+x))/*mem內第一個符合hstr+(sn+0)的字元*/
      {
        for(n=x+1,k=i+1;n<kwsn;n++,k++)/*再找出從第2到第sn個符合的字元*/
          if(*(mem+k) != *(kws+n))/*有不符合的字元即跳出*/
            break;
        /*結束(跳出)迴路後判斷n值是否比對到第sn個字元*/
        if(n>=kwsn)/*已比對到第sn位元即已找到字串*/
          return(i);
        else/*沒找到字串則再從第*(hstr+0)個字元開始找*/
          x=0;
      }
    }
  }
  else/*往後(順向)搜尋,FROM*/
  {
    x=0;/*順向時要搜尋的字串hstr是從第0個字元開始比對*/
    for(i=footp;i<endp;i++)/*從footp找到endp*/
    {
      if(*(mem+i) == *(kws+x))/*mem內第1個符合hstr+0的字元*/
      {
        for(n=x+1,k=i+1;n<kwsn;n++,k++)/*再找出從第2到第sn個符合的字元*/
          if(*(mem+k) != *(kws+n))/*有不符合的字元即跳出*/
            break;
        /*結束(跳出)迴路後判斷n值是否比對到第sn個字元*/
        if(n>=kwsn)/*已比對到第sn位元即已找到字串*/
          return(i);
        else/*沒找到字串則再從第*(hstr+0)個字元開始找*/
          x=0;
      }
    }
  }
  return(-1);
}


這樣我們就可以給他寫一段這樣的代碼來取得所需要的各步驟了
代碼: [選擇]
  char *fmap,*sendtmp;
  int fmapsz,sendtmpsz;

  fmap=lee_fout2tmp(fname,&fmapsz,NULL,NULL);/*取出設定檔*/
.....
.....
.....
  /*取得檔案內的目前所需(fkw,ekw所指定的)封包字串*/
  sendtmp=lee_rtvmem2sl(fmap,0,fmapsz,"[stp-1]\n","[/stp-1]",RETRB,&sendtmpsz);

lee_rtvmem2sl()的fkw的部份因為存在檔案裏面的首標籤都有個換列號且不需傳送給伺服器,且RETRB是只取身所以會排除該換列字元
再看一次:因為存成這樣,所以必須"[stp-1]\n"而不是"[stp-1]",因為lee_rtvmem2sl()會把第1個\n換列號給你一起取到sendtmp去....就多出一個\n了
代碼: [選擇]
[stp-1]
GET / ...
...
[/stp-1]


要"[stp-1]"則需存成這個樣子

[stp-1]GET / ...
...
[/stp-1]


這樣子有了解lee_rtvmem2sl()的用法了嗎?
而ekw末標籤不排除\n換列號則剛好上傳伺服器的\r\n的最後一個字元就是需要該\n字元所以不予排除



26
如果在台南公園賞花的話附近應該沒稱頭的餐廳....路邊攤倒是有幾個,其中一個是聞名全台的阿憨鹹粥

體育公園附近的五妃街滿多燈光美氣氛佳的餐廳,問題是體育公園沒花可賞=..=""

所以既要賞花又要附近有不錯的餐廳......成功大學應該是滿不錯的選擇(成大好多鳳凰花呀!)

成大附近有氣氛的餐廳集中點大概就是大學路上麥當勞旁邊的巷子裡面有幾間滿符合您的需求

且離台南公園也不算遠,還有消費也還OK,不會貴到嚇死人,氣氛也很好唷^^y

而且重點是如果餐廳真的找不到滿意的....最不濟還有個麥當勞可以應付小朋友



27
C/C++程式設計討論區 / C語言-網路的封包
« 於: 2010-05-26 15:17 »
把這陣子研究用C語言與網路上的伺服器一問一答的工具和大家分享一下
如果有觀念錯誤或不對的地方請先進前輩們不吝指教,感謝^^!


首先....要能以"網址反查出網址"??這是在說什麼呀?
喔!簡單講就是在程式裏面不能以例如yahoo.com.tw或google.com當成參數來連上網路
所以您必須要有:
代碼: [選擇]
main()
{
  hostname[]="yahoo.com.tw";
  char *addr;
  int i;
  
  addr=malloc(128);
  memset(addr,'\0',127);
  i=lee_hostname2addr(hostname,addr);
  printf("********** i=%d addr=%s hostname=%s **********\n",i,addr,hostname);
}

int lee_hostname2addr(char *hostname,char *addrs)
{
  struct hostent *hp;
  struct in_addr in;
  struct sockaddr_in local_addr;

/*printf("hostname=%s \n",hostname);
*/
  if(!(hp=gethostbyname(hostname)))
  {
    fprintf(stderr,"lee_hostname2addr()反查錯誤!hostname參數需先以menset()函數清空的空間\n");
    return(-1);
  }
  memcpy(&local_addr.sin_addr.s_addr,hp->h_addr,sizeof(hp->h_addr));
  in.s_addr=local_addr.sin_addr.s_addr;
  strcpy(addrs,inet_ntoa(in));

/*printf("IP=%s addrs=%s size=%d ...lee_hostname2addr\n",inet_ntoa(in),addrs,sizeof(hp->h_addr));
*/
  return(1);
}

/*接受addr+port字串將之拆成addr及port
如176.38.182.18:8044這樣的一個字串會被拆成176.38.182.18--->以字串型態傳回
及8044--->轉成數字後設定給*po*/
char *lee_addrport(char *host,int *po)
{
  char *addr,*port;
  int di,sn,i,n;

  sn=strlen(host);
  di=lee_memchunt(host,":",0,strlen(host),FROM);
  addr=calloc(sizeof(char),di+1);
  port=calloc(sizeof(char),sn-di);

  for(i=0;i<di;i++)
    *(addr+i)=*(host+i);
  for(i=di+1,n=0;i<sn;i++,n++)
    *(port+n)=*(host+i);
//printf("host=%s addr=%s port=%s \n",host,addr,port);
  *po=atoi(port);
  free(port);
  return(&*addr);
}


然後就可以跟他來個一問一答了
首先是問的部份
代碼: [選擇]
/*
使用者端傳送資料
*/
//void lee_send(int fd,char *fmap,int mapsz,char *fkw,char *ekw)
void lee_send(int fd,char *sendmem,int sendmemsz)
{
  char *tmp;
  int i,tmpsz;

 /*除錯*/
printf("\n[傳送開始]***********************************************************[傳送開始]\n");
/**/
  /*傳去的資料量要減一是字串陣列的末尾'\0'字元否則封包都會多傳一個'\0'  */
/*  if(write(fd,tmp,tmpsz-1)>0 )
    printf("錯誤:傳送失敗\n");
/**/
/*  if(send(fd,tmp,tmpsz-1,0) < 0)
    printf("錯誤:傳送失敗\n");
/**/
  if(write(fd,sendmem,sendmemsz)<=0 )
    printf("錯誤:傳送失敗\n");
/*除錯*/
for(i=0;i<sendmemsz;i++)
  printf("%c",*(sendmem+i));
printf("[傳送完畢]***** lee_send()... sendmemsz=%d *****[傳送完畢]\n",
       sendmemsz);
/**/

//  free(tmp);
}

再來當然是接收他的答了,這裡可能稍微複雜一點,因為發回來的資料可能
1.資料有壓縮過
2.資料編碼方式跟您目前系統的不一樣
3.資料的長度到底是多少,該宣告多大的空間來接收
4.目前還沒遇到的其他各種狀況

關於第1點前陣子有討論過了有興趣可以看一下
http://phorum.study-area.org/index.php/topic,61245.0.html

這裡貼一下比較"正常狀況下"可以解決第3點問題的代碼
代碼: [選擇]
char *lee_recvc(int fd,int *recvsz)
{
  char ch[8];
  char *tmp;
  int i,gi,page;


  page=1;
  tmp=malloc((1024*page) * sizeof(char));/*宣告空間*/
  *recvsz=gi=0;
/*除錯*/
printf("\n[接收開始]***********************************************************[接收開始]\n");
/**/
  while(/*recv(fd,ch,1,0)>0*/ read(fd,ch,1)>0 )/*接收資料*/
  {
    *(tmp+gi)=ch[0];//只複製一個字元時這樣寫應該比strncpy(tmp+gi,ch,1);快很多
    gi+=1;
    if(gi > page*1024)
    {
      page+=1;
      tmp=realloc(tmp,(1024*page));
    }
  }
  *recvsz=gi;
  if(lee_memchunt(tmp,"Could not connect Database",0,gi,FROM) !=-1)
            printf("Could not connect Database  對方主機無回應!\n");

/*除錯*/
for(i=0;i<gi;i++)  printf("%c",*(tmp+i));
printf("\n[接收完畢]***** lee_recv()...page=%d gi=%d *recvsz=%d *****[接收完畢]\n",
       page,gi,*recvsz);
/**/
  return(&*tmp);
}

然後是整合問與答兩者的連線函數
代碼: [選擇]
char *lee_http(char *haddr,
               char *sendtmp,int sendtmpsz,
               int *recvsz/*int code*/)
{
  struct sockaddr_in address;
  int fd,len;
  char *addr,*recvtmp;
  int hap,port;


  if(haddr==NULL)
  {
    *recvsz=0;
    recvtmp=calloc(sizeof(char),1);
    return(recvtmp);
  }

//printf("lee_http()...haddr=%s[%d] addr=%s port=%d \n",haddr,strlen(haddr),addr,port);
  /*addr格式是xx.xx.xx.xx:zzzz 其中的:zzzz是指埠號,以*/
  if((hap=lee_memchunt(haddr,":",0,strlen(haddr),FROM)) !=-1)
    addr=lee_addrport(haddr,&port);//將addr及埠號分解
  else
  {
    addr=haddr;
    port=80;
  }
//printf("lee_http()...haddr=%s addr=%s port=%d \n",haddr,addr,port);


  /*建立連線*/
  fd = socket(AF_INET,SOCK_STREAM, 0);
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = inet_addr(addr);
  address.sin_port = htons(/*80*/port);
  len = sizeof(address);
  if(connect(fd, (struct sockaddr *)&address, len) == -1)
    printf("錯誤:連線失敗\n");
  /*傳資料給伺服器*/
  lee_send(fd,sendtmp,sendtmpsz);
  /*接收伺服器的資料*/
//  recvtmp=lee_recv(fd,&*recvsz);
recvtmp=lee_recvc(fd,&*recvsz);

printf("\nlee_http()...haddr=%s addr=%s port=%d \n",haddr,addr,port);



  close(fd);/*中斷連線*/
  if(hap!=-1)
    free(addr);

  return(recvtmp);

}



等一下!等一下!......這裡說的一問一答到底都問些啥答些啥
其實就是我們以Wireshark所擷取的封包是也,把所擷取的封包照著發一次就好啦!
不過Wireshark擷取的封包必須先處理一下才能拿來用
要不然您也可以學我以前看著螢幕一個字一個字的照著敲然後用strcat()串接起來發出去
不過保證您玩個三天準備看醫生~~~~算了,不囉唆來看看怎麼取用Wireshark擷取的封包吧

首先當然是要有Wireshark啦,什麼!你沒有!!!google一下就有啦^^!
好的,這裡不是Wireshark教學所以自己網路上學一下,其實沒很困難,只要您能從上面看到這裡
相信也是"住巷子裡的"所以抓下來的封包就給他存起來吧

如果您是在win系統存起來的應該是*.pcap的檔案
這時請不要帥氣的左鍵連點兩下點開他而是以右鍵點一下,然後選[開啟檔案]->[WordPasd]
什麼,用Word開啟他....是的....其實用筆記本開就可以了=.=
然後給他另存新檔,檔案類型保持(或選擇) 文字文件
存起來的檔案就大概長這樣子
代碼: [選擇]
??\##P?�J??P#��###U#�K��##?##?###??###?{?d## ?#!E##�jY@#@##|o�#
??\##P}??�Z�P#��?##GET /images/leelib/xyzxxx.gif HTTP/1.1
Accept: */*
Accept-Language: zh-tw
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.4; InfoPath.1)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

U#�K v #########?{#??#�d## ##!E##��/@#?��??\o�#
#P#?�Z�}?�P##��##HTTP/1.1 304 Not Modified
Date: Thu, 20 May 2010 10:56:19 GMT
Server: Apache/2.2.3 (Unix) PHP/5.2.5
Connection: close

(以上封包有略為修改)

然後把GET部份的封包用lee_http()發出去就能得到HTTP/1.1 304 Not Modified這個相同的回應了嗎?
基本上是這樣沒錯的,不過其中有個"眉角"
就是您必須在每一行資料列後面跟著一個"\r\n"這樣的換列字元
不過這個"\r\n"您直接敲進去又不行,也就是說您把他改成這樣子
代碼: [選擇]
GET /images/leelib/xyzxxx.gif HTTP/1.1\r\n
Accept: */*\r\n
Accept-Language: zh-tw\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.4; InfoPath.1)\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: Keep-Alive\r\n
\r\n
這肯定是行不通的,因為這個\r\n是"兩個字元",如果直接在文書處理器敲進去的則是4個字元的\r\n

這時如果您手上有vi或另一台電腦是Linux(裏面有vi)那麼將WordPasd存起來的那個檔案利用gmaile傳到Linux電腦上...
(不一定要靠gmaile啦,不過我都是用gmaile傳的,因為.......他免費=..=")

然後如果有轉碼問題(像我ubuntu附的文字編輯器無法自動辨識)則可以用OpenOffice開啟(開的時候會自動轉碼)
然後給他存下去,當然以保留目前格式方式存

再來以vi 打開這個檔案時您會發現在每一列的後面有個奇怪符號像這個樣子
代碼: [選擇]
GET /images/leelib/xyzxxx.gif HTTP/1.1^M
Accept: */*^M
Accept-Language: zh-tw^M
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.4; InfoPath.1)^M
Accept-Encoding: gzip, deflate^M
Connection: Keep-Alive^M
^M
是的!你得到他了
不過.....這一個^M你就算自己敲上去也沒用
因為他的顏色會明顯與您自己敲進去的字元的顏色不一樣(但這個字元在vi內是可以複製的)



這個\r\n還有第2種方法可以取得,前面有說過用strcat()函數串接吧
代碼: [選擇]
strcat(tmp,"GET /images/leelib/xyzxxx.gif HTTP/1.1\r\n");
strcat(tmp,"Accept: */*\r\n");
.....
.....
這樣子的方式其實也是可以的,不過如果我們如果可以把每一個GET或POST動作存在檔案裏面變成其中的一個步驟而已
那麼........事情應該會變得簡單多了
當然,讓事情變"簡單"以前,肯定是有點小複雜的,這就是我們要研究的地方啦.....待續



28
雜七雜八 / 回覆: 請問他怕?
« 於: 2010-05-13 12:09 »
起先也不懂

不過到刪除存證區後~~~終於懂這個梗了 8)

29
Content-Length
是對方主機傳來的回應其描述是檔案大小,這樣說沒錯

不過我現在實際遇到的情況卻是
代碼: [選擇]
HTTP/1.1 200 OK

Date: Sun, 25 Apr 2010 04:44:46 GMT

Server: Apache/2.2.3 (Unix) PHP/5.2.5

X-Powered-By: PHP/5.2.5

Content-Length: 3613

Connection: close

Content-Type: text/html; charset=utf-8

照這個表頭,此封包往下再讀3613Byte應該沒錯吧

不過實際情況是在這一頁面的很後面有
<input type=HIDDEN name="uid" value="4e6896f750cf0d1f">
類似這樣一條,裏面有個uid碼必須在這裡抓到用以替換到以後的(偽)GET封包,否則後面的頁面都不用玩了
然而如果傻傻的只照其抓3613Byte就抓不到了
當然,這可能只是特例,因為該站也不是很"公開"的一種網站啦^^!

Content-Encoding
不只有送出喔!我目前接到的大多是帶個Content-Encoding:gzip
不然我會以為那些亂碼是因為編碼(Big5,utf-8)問題產生的,不會想到要給他解壓

30
今天在處理另一站時發現封包的表頭有時候真的會誆人
比如
Content-Length: 3616
照前面(昨天)的想法是說還有3616Byte要讀取是吧
結果並不是
因為我之前有抓過這站,所以非常確定不只3616Byte(該頁要抓的uid字串剛好在滿後面)

那麼現在問題來了Content-Length 這項描述到底是做啥的?
或是還要參考 Content-Encoding 是否有gzip等壓縮格式描述才對?

頁: [1] 2 3 ... 28