当前位置:   article > 正文

windows网络进阶之listen参数含义_win listen

win listen

目录

        一、前言

二、listen参数

三、实战案例

1. 使用Sleep函数让线程暂停 

2. 案例代码展示

3. 编译生成exe文件        


一、前言

        一、前言

        在Windows网络编程中,在使用TCP时,listen函数它是一个重要的关键的步骤,使得套接字能够接收传入的连接请求,下面我主要通过实战案例讲解listen参数的含义。注:本章是一个进阶篇,前提是能够掌握基础windows网络编程概念。

二、listen参数

        listen 函数官方给的原型为:

int listen(SOCKET s, int backlog);

         这里有两个参数:

        1.SOCKET s

        这是一个已绑定(通过bind函数)的套接字,作用用于接收客户端的连接请求。这个参数比较好理解,我们重点讲解第二个参数。

        2.int backlog

        这是一个 int 类型的变量,官方给的解释为:挂起的连接队列的最大长度。

        通俗意义上来理解为:就是当一个客户端尝试连接到服务器时,如果服务器当前正忙于处理其他连接,那么这个连接请求会被放入一个队列中等待。而这个队列的能允许承受的最大大小为blcklog的大小决定。

        上面就是对 backlog 的解释,但是讲到这里,应该有很少人能够真正理解它的含义所在,下面我将要通过一个实战案例带你真正的体验它的作用。

三、实战案例

1. 使用Sleep函数让线程暂停 

        我们要展现 backlog 数字的效果,就必须让多个客户端来连接同一个服务器。而正常情况下,客户端在连接服务器发送消息后就断开连接了。此时的挂起队列长度最大一直为1,所以我们需要让服务器成功监听客户端后,客户端不会断开连接。

        这里我使用了一个 Sleep 函数让服务器监听成功后线程暂停在这里,代码如下:

  1. // 3. 监听
  2. if (listen(sockSrv, 5) == SOCKET_ERROR) // 5 是指最大的监听数目,执行到listen
  3. {
  4. printf("listen error = %d\n", GetLastError());
  5. return -1;
  6. }
  7. printf("delay 20 begin\n");
  8. Sleep(20000);
  9. printf("delay 20 end\n");

         上述代码是TCP服务器端代码的片段,这里我设置 backlog 为 5 ,在监听后程序暂停休眠 20 秒,程序开始启动,同时对 listen 函数进行错误判断,方面我们能过直观的观察错误。

2. 案例代码展示

        服务器端总代码:

  1. #include <stdlib.h>
  2. #include <winsock.h>
  3. #include <stdio.h>
  4. #include <iostream>
  5. #pragma comment(lib, "ws2_32.lib")
  6. int main()
  7. {
  8. printf("NetWork socket\n");
  9. #if 1
  10. // 0 初始化网络库
  11. // 初始化库
  12. WSADATA wsaData;
  13. int stu = WSAStartup(MAKEWORD(2, 2), &wsaData);
  14. if (stu != 0) {
  15. std::cout << "WSAStartup 错误:" << stu << std::endl;
  16. return 0;
  17. }
  18. #endif
  19. // 1. 安装电话机 socket
  20. SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);
  21. if (sockSrv == INVALID_SOCKET)
  22. {
  23. std::cout << "socket failed!" << GetLastError() << std::endl;
  24. WSACleanup(); //释放Winsock库资源
  25. return 1;
  26. }
  27. // 2, 分配电话号码
  28. SOCKADDR_IN addrSrv;
  29. addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 地址 IP地址any
  30. addrSrv.sin_family = AF_INET; // ipv4协议
  31. addrSrv.sin_port = htons(6000); // 端口号
  32. bind(sockSrv, (sockaddr *)&addrSrv, sizeof(SOCKADDR));
  33. // 3. 监听
  34. if (listen(sockSrv, 5) == SOCKET_ERROR) // 5 是指最大的监听数目,执行到listen
  35. {
  36. printf("listen error = %d\n", GetLastError());
  37. return -1;
  38. }
  39. printf("delay 20 begin\n");
  40. Sleep(20000);
  41. printf("delay 20 end\n");
  42. // 客户端的信息
  43. SOCKADDR_IN addrCli;
  44. int len = sizeof(SOCKADDR);
  45. while (true)
  46. {
  47. printf("begin accept\n");
  48. // 4. 分配一台分机去处理客户端的连接
  49. SOCKET sockCon = accept(sockSrv, (sockaddr*)&addrCli, &len);
  50. // 定义发送多个消息
  51. char sendBuff[100] = { 0 };
  52. //sprintf_s(sendBuff, 100, "Hello World", inet_ntoa(addrCli.sin_addr));
  53. sprintf_s(sendBuff, 100, "Hello World");
  54. // 5. 开始通话,发送信息
  55. int iLen = send(sockCon, sendBuff, strlen(sendBuff), 0);
  56. // 6. 接收数据
  57. char recvBuff[100] = { 0 };
  58. recv(sockCon, recvBuff, 100, 0);
  59. printf("recvBuf = %s\n", recvBuff);
  60. closesocket(sockCon);
  61. }
  62. // 7.关闭服务器端
  63. closesocket(sockSrv);
  64. // 清理库
  65. WSACleanup();
  66. system("pause");
  67. return 0;
  68. }

         客户端总代码:

  1. #include <stdlib.h>
  2. #include <winsock.h>
  3. #include <stdio.h>
  4. #include <iostream>
  5. #pragma comment(lib, "ws2_32.lib")
  6. int main()
  7. {
  8. printf("NetWork socket\n");
  9. #if 1
  10. // 0 初始化网络库
  11. WSADATA wsaData;
  12. int stu = WSAStartup(MAKEWORD(2, 2), &wsaData);
  13. if (stu != 0) {
  14. std::cout << "WSAStartup 错误:" << stu << std::endl;
  15. return 0;
  16. }
  17. #endif
  18. // 1. 安装电话机 socket
  19. SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
  20. if (sockCli == INVALID_SOCKET)
  21. {
  22. std::cout << "socket failed!" << GetLastError() << std::endl;
  23. WSACleanup(); //释放Winsock库资源
  24. return 1;
  25. }
  26. // 2, 配置IP地址 和 端口号
  27. SOCKADDR_IN addrSrv;
  28. addrSrv.sin_family = AF_INET; // ipv4协议
  29. addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.7"); // 地址 IP地址any
  30. addrSrv.sin_port = htons(6000); // 端口号
  31. // 3. 连接服务器
  32. int res = connect(sockCli, (sockaddr*)&addrSrv, sizeof(sockaddr));
  33. if (res == SOCKET_ERROR)
  34. {
  35. printf("connect error = %d\n", GetLastError());
  36. system("pause");
  37. return -1;
  38. }
  39. // 4. 收发数据
  40. char recvBuff[100] = { 0 };
  41. recv(sockCli,recvBuff,100,0);
  42. printf("接收到的数据%s\n", recvBuff);
  43. const char sendBuff[100] = "asdasda";
  44. send(sockCli, (char*)sendBuff, 100, 0);
  45. // 5. 关闭连接
  46. closesocket(sockCli);
  47. // 清理库
  48. WSACleanup();
  49. system("pause");
  50. return 0;
  51. }
3. 编译生成exe文件
        

        第一步: 分别编译生成服务器端可执行代码和客户端可执行代码,操作步骤如图:

         

        编译成功如图所示。 

        第二步,在 debug 文件中夹种找到 exe 可执行文件。文件路径如图:

         

       第三步:先启动服务器程序,然后启动多个客户端器程序。多个客户端程序结果如图所示:

        最后总结,可见当启动第六个客户端程序时,出现错误   connect error = 10061 , 错误查找结果为:由于目标计算机积极拒绝,无法连接。说明超出了挂起的连接队列的最大长度,客户端无法连接。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/796735
推荐阅读
相关标签
  

闽ICP备14008679号