基本的TCP socket編程示例 -- 時間服務器及客戶端


服務器端的編寫

    1.  使用socket函數新建一個套接字,指定其 協議族family(AF_INET)、協議類型type(SOCK_STREAM)、協議(0, 系統根據family和type指定默認值)

    2.  使用bind函數將本地協議地址綁定到套接字上,

    3.  使用listen函數監聽客戶端發來的請求

    4.  使用accept函數循環接受客戶端的請求

    5.  使用send和recv函數發送和接收數據 

 

客戶端程序的編寫

     1.  使用socket函數創建一個套接字

     2.  使用connect函數連接服務器

     3.  使用send和recv發送和接受數據

 

示例如下:

 由於使用winsock之前需要初始化winsock DLL,所以我將winsock的初始化和釋放封裝到了一個類中,如下:

  1 // 初始化winsock

 2  #include <winsock2.h>
 3 #include <iostream>
 4  class SockInitializer{
 5      public:
 6         SockInitializer()
 7         {
 8             WORD versionRequired = MAKEWORD( 22);
 9             WSADATA wsaData;
10              int ret = WSAStartup(versionRequired, &wsaData);
11              if ( 0 != ret){
12                 std::cerr <<  " socket initialize failed ";
13                 exit( 1);
14             }
15         }
16         ~SockInitializer(){
17             WSACleanup();
18         }
19 };

 

接下來是服務器端的編寫:

注:關於listen的第二個參數backlog,我們可以為其指定一個環境變量,以隨時調整它的值 

 1  //  服務器端程序
 2  #include <winsock2.h>
 3 #include <cstdio>
 4 #include <ctime>
 5 
 6  using  namespace std;
 7 
 8 SockInitializer sockInitializer;    //  初始化winsock
 9 
10  int main()
11 {
12     SOCKET listenfd, connfd;
13     sockaddr_in serverAddr;
14     
15      char buf[ 100];
16     memset(buf,  0sizeof(buf));
17 
18      //  1. 建立一個socket
19      listenfd = socket(AF_INET, SOCK_STREAM,  0); 
20      if (INVALID_SOCKET == listenfd){
21         cerr <<  " invalid socket ";
22         exit( 1);
23     }
24 
25      //  2. 綁定到本地的端口
26      serverAddr.sin_family = AF_INET;
27     serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);   //  使用通配地址
28      serverAddr.sin_port = htons( 13);                  //  13是時間服務器的端口號
29 
30      int ret = bind(listenfd, (sockaddr*)&serverAddr,  sizeof(serverAddr) );
31      if (ret !=  0){
32         cerr <<  " error on bind: " << WSAGetLastError();
33         exit( 1);
34     }
35 
36      //  3. 開始監聽客戶端請求
37      listen(listenfd, SOMAXCONN);   //  listen的第二個參數指定了套接字排隊的最大連接個數,
38                                     //  我們為其指定 SOMAXCONN ,表示系統支持的最大連接個數
39       //  4. 循環接受客戶端的請求
40       while ( true){
41         cout <<  " accept ... " << endl;
42         connfd = accept(listenfd, (sockaddr*)NULL, NULL);   //  這里我們不需要接受客戶端的sockaddr, 因此指定為NULL
43           if (INVALID_SOCKET == connfd){
44             cerr <<  " error on accept: " << WSAGetLastError() << endl;
45              continue;
46         }
47         cout <<  " successfully accept socket: " << connfd << endl;
48         time_t ticks = time(NULL);
49         snprintf(buf,  sizeof(buf),  " %.24s\r\n ", ctime(&ticks) );
50         send(connfd, buf, strlen(buf),  0 );
51 
52         closesocket(connfd);
53     }
54 } 

  

客戶端程序:

  1 // 客戶端程序

 2  #include <winsock2.h>
 3 #include <cstdio>
 4 #include <iostream>
 5 
 6  using  namespace std;
 7 
 8 SockInitializer sockInitializer;  //  初始化winsock
 9 
10  int main( int argc,  char **argv)
11 {
12      if (argc !=  2){
13         cerr <<  " usage: client <ipaddress> ";
14         exit( 1);
15     }
16 
17      //  1. 創建套接字
18      SOCKET sockfd = socket(AF_INET, SOCK_STREAM,  0);
19      if (sockfd == INVALID_SOCKET){
20         cerr <<  " invalid socket ";
21         exit( 1);
22     }
23 
24      //  2. 連接至服務器
25      sockaddr_in serverAddr;
26     memset(&serverAddr,  0sizeof serverAddr);
27     serverAddr.sin_family = AF_INET;
28     serverAddr.sin_port = htons( 13);
29     serverAddr.sin_addr.s_addr = inet_addr(argv[ 1]);
30 
31      int ret = connect(sockfd, (SOCKADDR*)&serverAddr,  sizeof serverAddr);   //  指定服務器的地址
32       if ( 0 != ret){
33         cout <<  " error on connect: " << WSAGetLastError();
34         exit( 1);
35     }
36 
37      //  3. 接受數據
38       char buf[ 100];
39      int n;
40      while (  0 != (n = recv(sockfd, buf,  sizeof buf,  0) ) ){
41         buf[n] =  ' \0 ';
42         cout << buf;
43     }
44 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM