亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? svrsocket,cltsocket控件源碼.htm

?? ServerSocket,ClientSocket控件源碼,講述內部實現原理
?? HTM
?? 第 1 頁 / 共 3 頁
字號:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>New Page 1</title>
</head>

<body>

<p align="center"><font size="5">ServerSocket,ClientSocket控件源碼</font></p>
<table border="1" width="100%" bgcolor="#C0C0C0">
  <tr>
    <td width="100%">ServerSocket,ClientSocket控件源碼&nbsp;<br>
      <br>
      本篇將通過一次Socket通信操作來對ServerSocket和ClientSocket這兩個控件的源碼進行一次閱讀,希望能理出一個脈絡來,以供大家參考。其實說得確切一點,應該是對Scktcomp這個單元進行解讀,但由于這個單元的代碼太多了,所以不可能面面俱到,我試圖以非阻塞式的通信來一步步說明它們是怎么樣封裝WinSock的API的,至于阻塞式的,在ServerSocket和ClientSocket并不常用,所以這一篇就不打算說了,可能源碼中會有一些忽略掉,以后有時間來補一篇阻塞式的閱讀吧。雖然現在Delphi已經用Indy控件替換了SS和CS等網絡控件,但畢竟這兩個控件是對Socket函數進行封裝,學習它怎么樣封裝也好吧。<br>
      <br>
      在這之前,須對WinSock有一個大概的了解,但也僅止大概,對Socket編程有一個總體的掌握行了,畢竟那不是我的能力所及。想要系統一點的學習Socket,可以去網上下WinSocket的中文文檔以及參考MSDN。<br>
      <br>
      以下是說明這個過程中各個函數的聲明<br>
      <br>
      在開始使用WinSock的Api的時候,必須加載WinSock Dll的相應版本,這時用到的函數是:<br> 
      <br>
      int WSAStartup (<br> 
  WORD wVersionRequested,&nbsp;<br>
  LPWSADATA lpWSAData&nbsp;<br>
      );<br>
      wVersionRequested指定用到的WinSock的最低版本,高字節指定副版本,低字節指定主版本,關于WinSock的版本,詳見MSDN。<br>
      <br>
      lpWSAData結構類型,系統把加載進去的版本信息添加到這個結構中。<br>
      <br>
      該函數成功返回0,不成功則返回幾個錯誤代碼之一<br>
      <br>
      這個函數和WSACleanup對應,查看MSDN<br>
      <br>
      從MSDN列出一個例子:<br>
      <br>
      WORD wVersionRequested;<br> 
      <br>
      WSADATA wsaData;<br> 
      <br>
      int err;<br> 
      <br>
      <br>
      <br>
      wVersionRequested = MAKEWORD( 2, 2 );<br> 
      <br>
      <br>
      <br>
      err = WSAStartup( wVersionRequested, &amp;wsaData );<br> 
      <br>
      if ( err != 0 ) {<br> 
      <br>
    /* Tell the user that we could not find a usable */<br> 
      <br>
    /* WinSock DLL.                                  */<br> 
      <br>
    return;<br>
      <br>
      }<br>
      <br>
      調用上面的函數之后,就可以用下面的函數來創建一個Socket了,Socket是WinSock定義的數據類型(整數),相當于句柄,用于標識系統中的每一個Socket連接<br>
      <br>
      SOCKET socket (<br> 
  int af,&nbsp;<br>
  int type,&nbsp;<br>
  int protocol&nbsp;<br>
      );<br>
      Af協議標志,Internet協議族的標志是PINET。<br>
      <br>
      Type 協議類型志,SOCISTREAM表明是面向連接的字節流類型,SOCIDGRAM表明是面向無連接的數據報類型。<br> 
      <br>
      Protocol Socket采用的協議類型,如果采用IPPROTO_TCP常數就是采用了TCP協議。<br> 
      <br>
      如果調用失敗,會返回INVALID_SOCKET值,正常的Socket取值范圍是1~INVALID_SOCKET-1;<br>
      <br>
      下面的函數將Socket與特定的主機進行綁定:<br>
      <br>
      int bind (<br> 
  SOCKET s,&nbsp;<br>
  const struct sockaddr FAR*  name,&nbsp;<br>
  int namelen&nbsp;<br>
      );<br>
      S就是一個Socket,由Socket()函數返回得到的。<br>
      <br>
      Name是sockaddr結構的變量<br>
      <br>
      Namelen是Name結構的長度。<br>
      <br>
      如果函數調用成功,將返回0,如果不成功,將返回SOCKET_ERROR,可以從WSAGetLastError.函數獲得錯誤代碼。<br>
      <br>
      現在說sockaddr這個結構,在Winsock中其實有兩個功能相似的結構,它們是:<br>
      <br>
      struct sockaddr {<br> 
      <br>
        u_short    sa_family;<br> 
      <br>
        char       sa_data[14];<br> 
      <br>
      };<br>
      <br>
      struct sockaddr_in {<br> 
      <br>
        short   sin_family;<br> 
      <br>
        u_short sin_port;<br> 
      <br>
        struct  in_addr sin_addr;<br> 
      <br>
        char    sin_zero[8];<br> 
      <br>
      };<br>
      <br>
      這兩個結構在Delphi中被聲明為一個變體記錄,這兩個指定通信的本地主機地址,本地協議端口,另外還有通信過程中使用的協議類型。<br>
      <br>
      其中:sin_family規定了哪個協議用來實現套按字連接。WinSock必須設置常數AF_INET<br>
      <br>
      sin_port;:WinSock應用程序使用的端口號<br>
      <br>
      sin_addr:這個是32位IP地址<br>
      <br>
      sin_zero[8];這個保留,沒有使用。<br>
      <br>
      Server端必須調用Bind()函數,設計時可以將地址設定為INADDR_ANY,這樣WinSock會自動加入機器正確的地址.<br>
      <br>
      以下是客戶端向服務端連接時調用的函數<br>
      <br>
      int connect (<br> 
  SOCKET s,&nbsp;<br>
  const struct sockaddr FAR*  name,&nbsp;<br>
  int namelen&nbsp;<br>
      );<br>
      函數里的參數和bind()一個,不多說了,函數成功時返回0,否則返回SOCKET_ERROR。<br>
      <br>
      服務端在Bind之后,調用下面函數進行監視。<br>
      <br>
      int listen (<br> 
  SOCKET s,&nbsp;<br>
  int backlog&nbsp;<br>
      );<br>
      其中backlog是可以建立的最大連接數,如果值設為SOMAXCONN,將由Socket的服務提供商設定一個合理的值,這個值不確定。<br>
      <br>
      函數成功時返回0,否則返回SOCKET_ERROR。<br>
      <br>
      當客戶端連接服務端,服務端調用下面函數接收客戶的請求,并向客戶機發送應答信息<br>
      <br>
      SOCKET accept (<br> 
  SOCKET s,&nbsp;<br>
  struct sockaddr FAR* addr,&nbsp;<br>
  int FAR* addrlen&nbsp;<br>
      );<br>
      其中中addr是用來保存客戶機地址信息的指針<br>
      <br>
      Addrlen是addr的長度一般是Sizeof(addr)<br>
      <br>
      如果函數成功,則返回一個Socket,這個Socket才是與客戶實際通信的套接字,原來的那個Socket繼續監視其他客戶端的連接<br>
      <br>
      以下幾個是用個服務機和客戶機通信的函數,<br>
      int send (SOCKET s,const char FAR * buf, int len,int flags );<br> 
      在面向連接的情況下發送數據<br>
      int recv (SOCKET s, char FAR* buf,  int len, int flags );<br> 
      在面向連接的情況下接收數據<br>
      另外還有sendto和recvfrom用于無連接情況,具體查MSDN<br>
      其中Buf是發送或接收的緩沖區,Len是緩沖區的大小,Flags是網絡呼叫產生方式標志,值可以為0,MSG_DONTROUTE或 MSG_OOB用途具體看MSDN。<br> 
      通信完畢后,需要關閉Socket,函數聲明如下:<br>
      int closesocket (<br> 
  SOCKET s&nbsp;<br>
      );<br>
      在程序的最后,需要調用下面的函數,結束WinSock DLL<br> 
      int  WSACleanup (void);<br> 
      函數成功時返回0,否則返回SOCKET_ERROR。<br>
      <br>
      <br>
      下面開始TServerSockett和TClientSocket的原代碼閱讀:<br>
      不過在分析之前,先要明白,對于WinSock的封裝其實是由ScktComp單元的幾個類一起完成的,它們的關系是:<br>
      <br>
      TServerSocket繼承于TCustomServerSocket<br>
      <br>
      TCustomServerSocket繼承于TCustomSocket<br>
      <br>
      TCustomSocket繼承于TAbstractSocket而TAbstractSockeet的上級則是TComponent了<br>
      <br>
      TClientSocket繼承于TCustomSocket<br>
      <br>
      另外還有幾個類:<br>
      <br>
      TServerWinSocket和TClientWinSocket以及TServerClientWinSocket繼承TCustomSocket<br>
      <br>
      它們才是真正封裝Socket的類。作為上面提到的類的成員存在<br>
      <br>
      此外還有幾個用于阻塞式傳輸的類。這里就忽略不講了,以后有機會再補上來吧。&nbsp;<br>
      <br>
      <br>
      <br>
      以ServerSocket和ClientSocket的一次操作流程來跟蹤它們的源代碼,看看他們是怎么樣封WinSocket的。以非阻塞方式來例子。<br>
      <br>
      <br>
      <br>
      1.  ServerSocket要創建,構造函數如下:<br> 
      <br>
      (11)<br>
      <br>
      constructor TServerSocket.Create(AOwner: TComponent);<br> 
      <br>
      begin<br>
      <br>
  inherited Create(AOwner);<br> 
      <br>
  FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);<br> 
      <br>
  InitSocket(FServerSocket);<br>
      <br>
  FServerSocket.ThreadCacheSize := 10;<br> 
      <br>
      end;<br>
      <br>
      inherited Create(AOwner);是繼承自TComponent的構造函數。<br> 
      <br>
      接下來創建它的一個成員,這是一個TServerWinSocket的對象,這個才是真正封裝SocketApi的類,等一個討論它。事實上這個構造函數繼承自它的父類TCustomServerSocket<br>
      <br>
      接下來調用InitSocket(FServerSocket);這是ServerSocket的祖先類TAbstractSocket的一個方法,傳入參數是成員FserverSocket完成的功能是將ServerSocket的事件指針指向TServerWinSocket的事件,使其能處理Socket觸發的事件。<br>
      <br>
      最后,設置FServerSocket允許連接的線程數,這里為10。<br>
      <br>
      <br>
      <br>
      好,現在回過頭來看看FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);做了什么:<br> 
      <br>
      (111)<br>
      <br>
      constructor TServerWinSocket.Create(ASocket: TSocket);<br> 
      <br>
      begin<br>
      <br>
  FConnections := TList.Create;<br> 
      <br>
  FActiveThreads := TList.Create;<br> 
      <br>
  FListLock := TCriticalSection.Create;<br> 
      <br>
  inherited Create(ASocket);<br> 
      <br>
  FAsyncStyles := [asAccept];<br> 
      <br>
      end;<br>
      <br>
      首先創建兩個TList對象,一個是FConnections,代表各個處理客戶連接的Socket,它對應于屬性:property Connections[Index: Integer]: TCustomWinSocket,你可以通過這個屬性對各個客戶連接進行操作。FActiveThreads 管理由Connections 數組確定的的客戶端連接線程TServerClientThread,它對應的屬性是ActiveThreads,這個是只讀屬性,返回當前正在使用的TServerClientThread對象的個數。接下來創建互斥量對象,用于線程同步的處理。<br> 
      <br>
      到這里又調用其父類的構造函數,傳遞的參數就是ServerSocket給的值INVALID_SOCKET,(想想上面提到的這個值的意義)<br>
      <br>
      好,再繼續跟蹤,到其父類的構造函數去看一下,我們這時應該保留一個問題,按照WinSock的編程模式,剛開始應該是初始化Winsock.DLL,并調用綁定監聽函數,這些API是什么在地方被調用呢?<br>
      <br>
      (1111)<br>
      <br>
      constructor TCustomWinSocket.Create(ASocket: TSocket);<br> 
      <br>
      begin<br>
      <br>
  inherited Create;<br> 
      <br>
  Startup;<br>
      <br>
  FSocketLock := TCriticalSection.Create;<br> 
      <br>
  FASyncStyles := [asRead, asWrite, asConnect, asClose];<br> 
      <br>
  FSocket := ASocket;<br> 
      <br>
  FAddr.sin_family := PF_INET;<br> 
      <br>
  FAddr.sin_addr.s_addr := INADDR_ANY;<br> 
      <br>
  FAddr.sin_port := 0;<br> 
      <br>
  FConnected := FSocket &lt;> INVALID_SOCKET;<br> 
      <br>
      end;<br>
      <br>
      首先調用TObject的構造函數,<br>
      <br>
      再調用Sartup;分析完這個函數再看里面的代碼,這里可以猜測它里面會調用WSAStartup函數。<br>
      <br>
      接下來看到從ServerSocket傳過來的參數指定給了TCustomWinSocket的成員,還有下面幾個成員的設置,可以肯定,這里是對Socket進行初始化,結合開頭所講的知識,再看看源代碼。應該不難理解了吧。<br>
      <br>
      再看看Startup的源碼:<br>
      <br>
      (11111)<br>
      <br>
      procedure Startup;<br> 
      <br>
      var<br>
      <br>
  ErrorCode: Integer;<br> 
      <br>
      begin<br>
      <br>
  ErrorCode := WSAStartup($0101, WSAData);<br> 
      <br>
  if ErrorCode &lt;> 0 then<br> 
      <br>
    raise ESocketError.CreateResFmt(@sWindowsSocketError,<br> 
      <br>
      [SysErrorMessage(ErrorCode), ErrorCode, 'WSAStartup']);<br> 
      <br>
      end;<br>
      <br>
      這是一個全局函數,看到其中一行重要的代碼了,<br>
      <br>
      ErrorCode := WSAStartup($0101, WSAData);WinSock就是在這里被初始化的。<br> 
      <br>
      而在服務端沒有建立監聽之時,Socket就在上面被默認設置了。<br>
      <br>
      好,現在ServerSocket的成員FserverSocket的創建就完成了,再回到最上面,<br>
      <br>
      FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);之后,便是<br> 
      <br>
      InitSocket(FServerSocket);了,看看它的代碼:<br>
      <br>
      (12)<br>
      <br>
      procedure TAbstractSocket.InitSocket(Socket: TCustomWinSocket);<br> 
      <br>
      begin<br>
      <br>
  Socket.OnSocketEvent := DoEvent;<br> 
      <br>
  Socket.OnErrorEvent := DoError;<br> 
      <br>
      end;<br>
      <br>
      正好和上面所說的一樣,現在可以認為當Socket發生了事件(比如連接,接收等)之后,就是調用了DoEvent了,錯誤發生了也一樣。不妨看看DoEvent代碼:<br>
      <br>
      (121)<br>
      <br>
      procedure TAbstractSocket.DoEvent(Sender: TObject; Socket: TCustomWinSocket;<br> 
      <br>
  SocketEvent: TSocketEvent);<br> 
      <br>
      begin<br>
      <br>
  Event(Socket, SocketEvent);<br> 
      <br>
      end;<br>
      <br>
      里面是調用Event,再看看Event的聲明:<br>
      <br>
      procedure Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);virtual; abstract;<br> 
      <br>
      這是一個抽象函數,由此可以知道,TAbstractSocket是一個抽象的類,它只是封裝了一般的操作,具體地都留到了它的子類中去了,所以它的子類一定覆蓋了這個Event方法,而DoEvent中調用的Event實際上就是調用它子類的Event方法,這個就是典型的模板模式。<br>
      <br>
      好,看看它的子類有沒有覆蓋這個方法,果然在TCustomSocket中看到了這個方法,并實現了它,看看它的源代碼:<br>
      <br>
      (1211)<br>
      <br>
      procedure TCustomSocket.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);<br> 
      <br>
      begin<br>
      <br>
  case SocketEvent of<br> 
      <br>
    seLookup: if Assigned(FOnLookup) then FOnLookup(Self, Socket);<br> 
      <br>
    seConnecting: if Assigned(FOnConnecting) then FOnConnecting(Self, Socket);<br> 
      <br>
    seConnect:<br>
      <br>
      begin<br>
      <br>
        FActive := True;<br> 
      <br>
        if Assigned(FOnConnect) then FOnConnect(Self, Socket);<br> 
      <br>
      end;<br>
      <br>
    seListen:<br>
      <br>
      begin<br>
      <br>
        FActive := True;<br> 
      <br>
        if Assigned(FOnListen) then FOnListen(Self, Socket);<br> 
      <br>
      end;<br>
      <br>
    seDisconnect:<br>

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
综合中文字幕亚洲| 成人精品视频一区| 久久精品72免费观看| www.日韩av| 久久综合九色欧美综合狠狠| 18成人在线视频| 日本在线不卡视频| 日本电影欧美片| 国产欧美日本一区视频| 免费av成人在线| 麻豆精品在线视频| 欧美日韩一区二区三区不卡| 国产亚洲欧美在线| 天天色综合成人网| 91国产免费看| 综合久久久久久| 久久99精品视频| 亚洲18色成人| 成人精品一区二区三区中文字幕| 4438成人网| 亚洲最新视频在线观看| 99视频在线观看一区三区| 欧美成人三级在线| 丝袜a∨在线一区二区三区不卡| 成人免费毛片a| 国产亚洲欧美日韩在线一区| 九九国产精品视频| 26uuu亚洲综合色| 久久精品噜噜噜成人av农村| 欧美一区二区视频观看视频| 亚洲成a人片在线观看中文| 欧洲精品一区二区三区在线观看| 亚洲欧美中日韩| 成人国产电影网| 国产精品久久久久久久蜜臀| 成人精品一区二区三区四区| 国产精品理伦片| 色综合天天综合网天天看片| 亚洲天堂成人在线观看| 欧洲在线/亚洲| 亚洲图片自拍偷拍| 91精品国产一区二区人妖| 蜜芽一区二区三区| wwwwww.欧美系列| 成人午夜视频福利| 亚洲欧美偷拍卡通变态| 欧美性色综合网| 久久精品国产99久久6| 久久久综合视频| 99视频国产精品| 一区二区三区.www| 9191国产精品| 国产美女精品在线| 亚洲免费av在线| 91精品免费观看| 国产酒店精品激情| 亚洲图片激情小说| 欧美色综合影院| 久久国产夜色精品鲁鲁99| 国产免费观看久久| 欧美色精品在线视频| 精品系列免费在线观看| 中文字幕一区在线观看| 欧美日韩另类一区| 国精品**一区二区三区在线蜜桃| 国产日韩精品视频一区| 91福利国产成人精品照片| 老司机午夜精品99久久| 最新不卡av在线| 精品视频一区二区不卡| 久久精品国产精品亚洲综合| 亚洲欧美综合在线精品| 日韩一二三区不卡| 91麻豆免费观看| 蜜臀99久久精品久久久久久软件| 国产欧美精品一区aⅴ影院 | 国产成人精品一区二区三区四区 | 日韩一级免费观看| 97久久超碰国产精品电影| 另类小说一区二区三区| 亚洲一区二区在线免费看| 337p日本欧洲亚洲大胆色噜噜| 成人av网址在线| 久久精品理论片| 亚洲一区二区三区视频在线播放| 久久久久久久久蜜桃| 欧洲国产伦久久久久久久| 大陆成人av片| 久久国内精品视频| 肉丝袜脚交视频一区二区| 亚洲欧洲在线观看av| 久久久久97国产精华液好用吗 | eeuss鲁片一区二区三区| 奇米精品一区二区三区四区| 亚洲精品乱码久久久久久| 国产丝袜美腿一区二区三区| 日韩欧美aaaaaa| 5858s免费视频成人| 色综合视频在线观看| 成人综合在线网站| 国产精品69毛片高清亚洲| 日本伊人色综合网| 午夜视黄欧洲亚洲| 一区二区三区在线免费观看| 国产精品亲子伦对白| 欧美极品另类videosde| 久久影音资源网| 欧美精品一区二区三区蜜桃视频 | 波多野结衣视频一区| 国内精品国产成人国产三级粉色 | 夜夜亚洲天天久久| 国产精品久久久久久久久免费丝袜| 精品福利一区二区三区免费视频| 91精品国产91综合久久蜜臀| 欧美丰满少妇xxxxx高潮对白| 欧美性感一区二区三区| 色狠狠色噜噜噜综合网| 91免费看`日韩一区二区| 色综合久久久久| 欧美色偷偷大香| 欧美日韩小视频| 欧美日韩国产影片| 91精品国产综合久久精品app| 欧美人xxxx| 日韩女优视频免费观看| 精品国产一区二区在线观看| 久久嫩草精品久久久精品| 国产日产欧产精品推荐色| 国产精品情趣视频| 最新成人av在线| 亚洲成人午夜影院| 麻豆国产一区二区| 国产成a人亚洲精| 91麻豆6部合集magnet| 欧美性猛交xxxxxxxx| 欧美一区二区福利视频| 精品久久久久久久人人人人传媒 | 日韩欧美国产精品| 日韩欧美在线网站| 欧美一区二区三区公司| 欧美大胆人体bbbb| 中文字幕亚洲区| 亚洲国产精品精华液网站| 日韩 欧美一区二区三区| 极品美女销魂一区二区三区| 成人av网站在线观看| 欧美男女性生活在线直播观看| 欧美一卡在线观看| 国产精品毛片大码女人| 亚洲电影视频在线| 国产福利不卡视频| 91福利视频网站| 日韩欧美电影在线| 日本一区二区三区电影| 亚洲国产精品一区二区尤物区| 捆绑变态av一区二区三区| 色综合久久综合网| 精品蜜桃在线看| 亚洲三级小视频| 久久99精品久久久久久动态图| heyzo一本久久综合| 日韩精品自拍偷拍| 亚洲精品少妇30p| 国产自产v一区二区三区c| 色欧美88888久久久久久影院| 日韩亚洲欧美综合| 亚洲宅男天堂在线观看无病毒| 国产在线视频一区二区| 精品视频免费在线| 美女高潮久久久| 欧美日韩一区二区三区四区 | 免费成人av在线播放| www.99精品| 久久午夜色播影院免费高清| 亚洲一卡二卡三卡四卡无卡久久| 国产精品中文字幕日韩精品| 欧美日韩国产一区二区三区地区| 日本一区二区三区在线不卡| 男女性色大片免费观看一区二区| 91麻豆精东视频| 国产肉丝袜一区二区| 九一久久久久久| 日韩一卡二卡三卡国产欧美| 亚洲综合成人在线| 色噜噜狠狠色综合欧洲selulu | 久久久噜噜噜久久人人看 | 亚洲另类一区二区| 成人污视频在线观看| 日韩美女在线视频 | 国产在线不卡一区| 久久人人超碰精品| 亚洲成年人网站在线观看| 国产尤物一区二区| 精品久久久三级丝袜| 日本va欧美va瓶| 91麻豆精品国产无毒不卡在线观看| 最新不卡av在线| 色天天综合久久久久综合片| 最近日韩中文字幕| 日本电影欧美片|