基於 TCP Socket 的服務器與客戶端的簡單連接


簡單的講下流程:

  1. 服務器會創建一個監聽 socket, 用來監聽客戶端的連接請求,接着配置一下監聽 socket 的 IP、port、protocol
  2. 綁定配置好的信息 以及監聽 socket
  3. 綁定好之后就是監聽一下 服務器創建的 監聽 socket,限定一下隊列的最大連接數
  4. 監聽成功后就等待客戶端的連接請求
  5. 客戶端有連接請求進來就 把請求接進來 然后為它創建一個與其對應的 socket, 兩者之間建立一條數據通道
 
 文字不如代碼好看,接下來看看代碼是如何展示的:
 
// 所需包含的頭文件及庫

  #include <stdio.h>

  #include <string.h>

  #include <stdlib.h>

  #ifdef WIN32

  #include <winsock2.h>

  #include <windows.h>

  #pragma comment(lib, "WSOCK32.LIB")

  #endif

// end
 
// 服務器
// 包含收尾必要的 啟用 WinSockApi 功能 和 終止 WinSockApi 功能
    #ifdef WIN32
   // 應用程序 開始之前必須先 啟動這個,后面才能使用 winsock 的功能
   WORD version_requested = MAKEWORD(2, 2);
   WSADATA wsadata;
   int err = WSAStartup(version_requested, &wsadata); // 啟動 winsock 服務
   if (err != 0) {
      printf("Startup failed\n");
      return;
   }
  #endif
 
  Failed:
    if (server_socket != INVALID_SOCKET) {
         closesocket(server_socket); // 關掉 socket
    } 
  #ifdef WIN32
     WSACleanup(); // 終止 winsock 服務
  #endif
// end
 
// 中間部分

  // 創建一個 socket, 用來監聽客戶端的連接, TCP 的 socket  

  int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

  if (server_socket == INVALID_SOCKET)  {   

    goto Failed;  

  }

   printf("Starting bind socket at port %d ...\n", port);  

  // 配置信息  

  struct sockaddr_in addr;

     addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  // IP  

  addr.sin_port = htons(port);     // port

  addr.sin_family = AF_INET;     // protocol

  // end

 

  int ret = bind(server_socket, (const struct sockaddr*)&addr, sizeof(addr)); // 綁定 socket  

  if (ret != 0) {   

    printf("Bind %s:%d error\n", "127.0.0.1", port);   

    goto Failed;  

  }  

  printf("Bind %s:%d success\n", "127.0.0.1", port);

   printf("Starting listener on %d ...\n", port);  

  ret = listen(server_socket, 128); // 開始監聽這個 socket  , 限制隊列的最大連接數

  if (ret != 0) {   

    printf("Listening on %d failed\n", port);   

    goto Failed;  

  }  

  printf("Listening on %d success\n", port);

 

  fd_set server_fd_set; // 管理所有 socket 的集合  

  while (1) { // 使用 select 模型來等待處理 socket 事件   

    FD_ZERO(&server_fd_set); // 清空這個 socket 集合

    FD_SET(server_socket, &server_fd_set);  // 將監聽 socket 添加到集合里

       printf("Waiting...\n");   

    int ret = select(0, &server_fd_set, NULL, NULL, NULL); // 等待監聽集合里所有的句柄   

    if (ret < 0) {    

      printf("Select error\n");   

    }   

    else if (ret == 0) { // 表示超時: 實現應用程序的定時器    

      continue;   

    }

       printf("Wait for data\n");   

    // part1: 監聽端口進來的連接信息   

    if (FD_ISSET(server_socket, &server_fd_set)) { // 監聽端口有可讀數據    

      // 將端口監聽進來    

      struct sockaddr_in c_addr;    

      int len = sizeof(c_addr);    

      int client_socket = accept(server_socket, (struct sockaddr*)&c_addr, &len); // 創建和客戶端對應的 socket    

      if (client_socket != INVALID_SOCKET) {     

        printf("New client %s:%d comming\n", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));         

      }   

    }

// end
 
// 客戶端
  // 必要的啟用和結束 WinSockApi 功能就還是跟上面一樣

   // 創建一個與服務器連接的 socket, TCP socket  

  int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

  if (client_socket == INVALID_SOCKET) {   

    return -1;  

  }

   // 配置信息  

  struct sockaddr_in sockaddr;  

  sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  

  sockaddr.sin_port = htons(6000);  

  sockaddr.sin_family = AF_INET;  

  // end

   int ret = connect(client_socket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); // 連接 socket  

  if (ret != 0) {   

    printf("Connect error\n");   

    goto Failed;  

  }

   printf("Connect success\n");  

  system("pause");

  Failed :  

    if (client_socket != INVALID_SOCKET) {   

      closesocket(client_socket); // 關掉 socket  

    }

 

效果圖:

  服務器:

  

  客戶端:

  

到此結束咯!

方便他人,亦是方便自己!


免責聲明!

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



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