亚洲欧美第一页_禁久久精品乱码_粉嫩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一区二区三区免费野_久草精品视频
国内国产精品久久| 亚洲少妇最新在线视频| 美女免费视频一区| 欧美一级日韩不卡播放免费| 视频一区视频二区在线观看| 欧美男同性恋视频网站| 免费xxxx性欧美18vr| 亚洲精品在线电影| 成人国产视频在线观看| 亚洲精品国产无套在线观| 欧美精品精品一区| 国产美女在线观看一区| 亚洲欧洲精品天堂一级| 在线播放91灌醉迷j高跟美女 | 国产精品99久久久久久久vr| 精品国产免费久久| 99视频一区二区| 午夜精品久久久久久久久久久| 91精品国产一区二区人妖| 国产麻豆精品视频| 亚洲视频一区二区在线| 欧美一区二区三区成人| 国产盗摄视频一区二区三区| 亚洲美女免费视频| 欧美刺激午夜性久久久久久久| 91高清在线观看| 午夜精品一区二区三区电影天堂 | 色就色 综合激情| 日本欧美肥老太交大片| 中文字幕欧美日本乱码一线二线| 欧美最新大片在线看| 韩国av一区二区三区| 亚洲另类一区二区| 精品99999| 欧美婷婷六月丁香综合色| 国产福利不卡视频| 男男视频亚洲欧美| 一区二区三区国产精华| 国产视频一区二区在线观看| 欧美日韩国产在线观看| av在线一区二区| 久久精品国产第一区二区三区| 国产精品国产馆在线真实露脸| 欧美一区二区三区婷婷月色| 99久久精品国产导航| 国产麻豆欧美日韩一区| 日av在线不卡| 亚洲美女淫视频| 国产精品卡一卡二| 国产亚洲一区二区三区| 日韩一区二区三区视频| 欧美视频一区二| 91亚洲男人天堂| 成人福利视频网站| 国产真实乱子伦精品视频| 婷婷中文字幕综合| 亚洲欧美国产毛片在线| 国产精品国产三级国产普通话蜜臀| 在线播放91灌醉迷j高跟美女 | 国产视频一区二区三区在线观看| 欧美精品免费视频| 欧美视频中文一区二区三区在线观看| 丰满少妇久久久久久久| 国产电影精品久久禁18| 国产一区二区三区av电影| 老司机午夜精品99久久| 视频在线观看一区| 亚洲精品成人悠悠色影视| 国产欧美精品在线观看| 久久久精品影视| 国产亚洲综合av| 国产肉丝袜一区二区| 亚洲精品在线免费观看视频| 精品国产电影一区二区| 26uuu久久天堂性欧美| 日韩欧美成人午夜| 精品国产麻豆免费人成网站| 精品乱码亚洲一区二区不卡| 精品国产免费视频| 久久久亚洲高清| 欧美经典一区二区三区| 国产精品国产三级国产aⅴ入口| 欧美韩国一区二区| 国产精品另类一区| 综合久久久久久| 精品一区二区日韩| 国产精品一区二区视频| 成人午夜电影久久影院| 91麻豆成人久久精品二区三区| a4yy欧美一区二区三区| 91搞黄在线观看| 5858s免费视频成人| 欧美不卡123| 亚洲国产岛国毛片在线| 自拍偷拍亚洲欧美日韩| 亚洲午夜精品网| 日本色综合中文字幕| 久久国产精品99久久久久久老狼 | 中文字幕精品在线不卡| 亚洲日本韩国一区| 亚洲成精国产精品女| 美洲天堂一区二卡三卡四卡视频| 国产伦精品一区二区三区免费| 成人动漫一区二区| 欧美高清一级片在线| 久久久噜噜噜久久人人看 | 国产a久久麻豆| 91视频国产观看| 91精品黄色片免费大全| 久久久久88色偷偷免费| 亚洲卡通欧美制服中文| 免费看精品久久片| 99riav久久精品riav| 欧美一区2区视频在线观看| 国产欧美1区2区3区| 亚洲国产va精品久久久不卡综合| 精品无人码麻豆乱码1区2区| 懂色av一区二区三区免费看| 欧美日韩精品系列| 日本一区二区高清| 视频一区在线视频| 99视频一区二区| 精品国产免费久久| 亚洲午夜一区二区| 成人午夜激情影院| 日韩三级视频在线观看| 国产精品成人免费| 经典三级一区二区| 欧美视频在线播放| 国产精品久久99| 国产一区亚洲一区| 欧美日本不卡视频| 亚洲欧美日韩成人高清在线一区| 久久电影国产免费久久电影| 色狠狠一区二区三区香蕉| 精品三级av在线| 午夜精品久久一牛影视| 91在线看国产| 中文字幕欧美日韩一区| 久久99国产精品麻豆| 欧美三级在线视频| 国产精品福利一区| 国产乱淫av一区二区三区 | 国产福利一区二区| 日韩欧美亚洲国产精品字幕久久久| 亚洲乱码国产乱码精品精的特点| av在线播放一区二区三区| 欧美不卡视频一区| 免费日本视频一区| 欧美肥妇bbw| 婷婷国产v国产偷v亚洲高清| 色婷婷av一区二区三区软件 | 久久人人爽人人爽| 免费成人在线观看视频| 欧美日韩在线播| 亚洲一区二区欧美日韩| 色一区在线观看| 亚洲欧美综合在线精品| 不卡视频在线观看| 国产精品久久久久四虎| 成人做爰69片免费看网站| 久久欧美一区二区| 国产v综合v亚洲欧| 国产欧美日韩在线| 成人亚洲一区二区一| 国产精品美女久久久久高潮| 懂色av一区二区夜夜嗨| 欧美激情综合网| 99综合影院在线| 亚洲男人天堂一区| 欧美日韩一二区| 天天影视网天天综合色在线播放| 欧美丝袜第三区| 日韩av中文字幕一区二区| 欧美一级xxx| 狠狠色综合日日| 国产精品私人影院| 97国产一区二区| 亚洲国产婷婷综合在线精品| 欧美伦理电影网| 精品一区二区三区欧美| 久久免费偷拍视频| 成年人网站91| 亚洲国产精品久久人人爱蜜臀| 欧美精品免费视频| 国产乱人伦偷精品视频免下载| 国产欧美日韩另类视频免费观看| 成人av在线观| 亚洲一级电影视频| 日韩精品中文字幕一区| 成人免费看视频| 亚洲一区在线视频观看| 日韩免费观看高清完整版| 国产精品资源网| 樱花草国产18久久久久| 日韩欧美在线123| 91免费观看视频在线| 亚洲国产欧美日韩另类综合 | 国产精品入口麻豆原神| 色婷婷亚洲精品|