基于 TCP Socket 的服务器与客户端的简单连接

时间:2021-04-02 00:00:00

简单的讲下流程:

  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  

    }

 

效果图:

  服务器:

  基于 TCP Socket 的服务器与客户端的简单连接

  客户端:

  基于 TCP Socket 的服务器与客户端的简单连接

到此结束咯!

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