当前位置:   article > 正文

Windows下的网络编程_windows网络编程

windows网络编程

socket 接口已普遍存在于现代操作系统中

Windows 下的 socket 编程接口与 Linux 中几乎相同

不同之处

  • 返回值类型不同 (句柄类型)
  • 句柄不是文件描述符,Windows 中并不是一切皆文件

Windows 下 socket() 的用法

 Windows 网络编程接口

几点细微差异

通过 WSAStartup() 初始化系统环境 (最先调用)

socket(),accept() 错误返回 INVALID_SOCKET (不可默认为 -1)

bind(),listen() 错误返回 SOCKET_ERROR (不可默认为 -1)

connect(),send(),recv() 错误返回 SOCKET_ERROR (不可默认为 -1)

通过 WSACleanup() 清除系统环境 (最后调用)

Windows 网络编程的特殊说明

在工程属性中设置链接 ws2_32.lib

定义变量 WSADATA wd;

选择 socket 版本并初始化 WSAStartup(MAKEWORD(2,2),&wd);

  • Windows 中存在多个 socket 版本

Windows 客户端编程示例

Windows 服务端编程示例

Windows 网络编程示例

client.c

  1. #include <iostream>
  2. #include <winsock2.h>
  3. #pragma warning(disable : 4996)
  4. int main()
  5. {
  6. SOCKET sock = 0;
  7. struct sockaddr_in addr = { 0 };
  8. char input[32] = { 0 };
  9. char buf[128] = { 0 };
  10. int n = 0;
  11. WSADATA wd = { 0 };
  12. if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
  13. {
  14. printf("startup error\n");
  15. return -1;
  16. }
  17. sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  18. if (sock == INVALID_SOCKET)
  19. {
  20. printf("socker error\n");
  21. return -1;
  22. }
  23. addr.sin_family = AF_INET;
  24. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  25. addr.sin_port = htons(8888);
  26. if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
  27. {
  28. printf("connect error\n");
  29. return -1;
  30. }
  31. printf("connect succeed\n");
  32. while (1)
  33. {
  34. printf("Input: ");
  35. scanf("%s", input);
  36. send(sock, input, strlen(input) + 1, 0);
  37. n = recv(sock, buf, sizeof(buf), 0);
  38. if (n > 0)
  39. {
  40. printf("Receive data: %s\n", buf);
  41. }
  42. else
  43. {
  44. break;
  45. }
  46. }
  47. closesocket(sock);
  48. WSACleanup();
  49. return 0;
  50. }

server.c

  1. #include <iostream>
  2. #include <winsock2.h>
  3. #pragma warning(disable : 4996)
  4. int main()
  5. {
  6. SOCKET server = 0;
  7. struct sockaddr_in saddr = { 0 };
  8. SOCKET client = 0;
  9. struct sockaddr_in caddr = { 0 };
  10. int csize = 0;
  11. char buf[32] = { 0 };
  12. int r = 0;
  13. WSADATA wd = { 0 };
  14. if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
  15. {
  16. printf("startup error\n");
  17. return -1;
  18. }
  19. server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  20. if (server == INVALID_SOCKET)
  21. {
  22. printf("server socket error\n");
  23. return -1;
  24. }
  25. saddr.sin_family = AF_INET;
  26. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  27. saddr.sin_port = htons(8888);
  28. if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR)
  29. {
  30. printf("server bind error\n");
  31. return -1;
  32. }
  33. if (listen(server, 1) == SOCKET_ERROR)
  34. {
  35. printf("server listen error\n");
  36. return -1;
  37. }
  38. printf("start to accept\n");
  39. while (1)
  40. {
  41. csize = sizeof(caddr);
  42. client = accept(server, (struct sockaddr*)&caddr, &csize);
  43. if (client == INVALID_SOCKET)
  44. {
  45. printf("server accept error\n");
  46. return -1;
  47. }
  48. printf("client = %d\n", client);
  49. do
  50. {
  51. r = recv(client, buf, sizeof(buf), 0);
  52. if (r > 0)
  53. {
  54. if (strcmp("quit", buf) == 0)
  55. {
  56. break;
  57. }
  58. else
  59. {
  60. printf("Receive data: %s\n", buf);
  61. send(client, buf, strlen(buf) + 1, 0);
  62. }
  63. }
  64. } while (r > 0);
  65. closesocket(client);
  66. }
  67. closesocket(server);
  68. WSACleanup();
  69. return 0;
  70. }

程序运行结果如下:

问题

select() 是 Linux 系统特有的吗?

Windows 中的 select() 函数

Windows 中同样提供 select() 函数,且参数和 Linux 的版本完全相同

注意:Windows 中的 select() 函数,第一个参数没有任何意义 (仅为了兼容)

一个细微差异

Windows 中的 select() 专门为套接字而设计

  • fd_count 用于记录感兴趣的 socket 数量
  • fd_array 用于记录感兴趣的 socket 句柄值

Windows 中 select() 函数使用示例

Windows 中的多路复用服务端

 select-server.c

  1. #include <iostream>
  2. #include <winsock2.h>
  3. #pragma warning(disable : 4996)
  4. SOCKET server_handler(SOCKET server)
  5. {
  6. struct sockaddr_in addr = { 0 };
  7. int asize = sizeof(addr);
  8. return accept(server, (struct sockaddr*)&addr, &asize);
  9. }
  10. int client_handler(SOCKET client)
  11. {
  12. int ret = -1;
  13. char buf[32] = { 0 };
  14. ret = recv(client, buf, sizeof(buf) - 1, 0);
  15. printf("Receive: %s\n", buf);
  16. if (ret > 0)
  17. {
  18. buf[ret] = '0';
  19. if (strcmp(buf, "quit") != 0)
  20. {
  21. ret = send(client, buf, strlen(buf), 0);
  22. }
  23. else
  24. {
  25. ret = -1;
  26. }
  27. }
  28. return ret;
  29. }
  30. int main()
  31. {
  32. SOCKET server = 0;
  33. struct sockaddr_in saddr = { 0 };
  34. int num = 0;
  35. fd_set reads = { 0 };
  36. fd_set temps = { 0 };
  37. struct timeval timeout = { 0 };
  38. WSADATA wd = { 0 };
  39. if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
  40. {
  41. printf("startup error\n");
  42. return -1;
  43. }
  44. server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  45. if (server == INVALID_SOCKET)
  46. {
  47. printf("server socket error\n");
  48. return -1;
  49. }
  50. saddr.sin_family = AF_INET;
  51. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  52. saddr.sin_port = htons(8888);
  53. if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR)
  54. {
  55. printf("server bind error\n");
  56. return -1;
  57. }
  58. if (listen(server, 1) == SOCKET_ERROR)
  59. {
  60. printf("server listen error\n");
  61. return -1;
  62. }
  63. FD_ZERO(&reads);
  64. FD_SET(server, &reads);
  65. printf("start to accept\n");
  66. while (1)
  67. {
  68. timeout.tv_sec = 0;
  69. timeout.tv_usec = 10000;
  70. temps = reads;
  71. num = select(0, &temps, NULL, NULL, &timeout);
  72. if (num > 0)
  73. {
  74. for (int i = 0; i <= reads.fd_count; i++)
  75. {
  76. SOCKET sock = reads.fd_array[i];
  77. if (FD_ISSET(sock, &temps))
  78. {
  79. if (sock == server)
  80. {
  81. SOCKET client = server_handler(server);
  82. if (client != INVALID_SOCKET)
  83. {
  84. FD_SET(client, &reads);
  85. printf("accept client: %d\n", client);
  86. }
  87. }
  88. else
  89. {
  90. if (client_handler(sock) == -1)
  91. {
  92. FD_CLR(sock, &reads);
  93. closesocket(sock);
  94. }
  95. }
  96. }
  97. }
  98. }
  99. }
  100. closesocket(server);
  101. WSACleanup();
  102. return 0;
  103. }

Windows 下的 select() 函数,根据所监听文件描述符的个数遍历,相较于 Linux 的实现,遍历的次数更少,效率更高。

程序运行结果如下:

思考

 如何编写跨平台编译运行的网络程序?

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/147185
推荐阅读
相关标签
  

闽ICP备14008679号