赞
踩
Windows 下的 socket 编程接口与 Linux 中几乎相同
不同之处
通过 WSAStartup() 初始化系统环境 (最先调用)
socket(),accept() 错误返回 INVALID_SOCKET (不可默认为 -1)
bind(),listen() 错误返回 SOCKET_ERROR (不可默认为 -1)
connect(),send(),recv() 错误返回 SOCKET_ERROR (不可默认为 -1)
通过 WSACleanup() 清除系统环境 (最后调用)
在工程属性中设置链接 ws2_32.lib
定义变量 WSADATA wd;
选择 socket 版本并初始化 WSAStartup(MAKEWORD(2,2),&wd);
client.c
-
- #include <iostream>
- #include <winsock2.h>
-
- #pragma warning(disable : 4996)
-
- int main()
- {
- SOCKET sock = 0;
- struct sockaddr_in addr = { 0 };
- char input[32] = { 0 };
- char buf[128] = { 0 };
- int n = 0;
-
- WSADATA wd = { 0 };
-
- if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
- {
- printf("startup error\n");
-
- return -1;
- }
-
- sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (sock == INVALID_SOCKET)
- {
- printf("socker error\n");
-
- return -1;
- }
-
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- addr.sin_port = htons(8888);
-
- if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
- {
- printf("connect error\n");
-
- return -1;
- }
-
- printf("connect succeed\n");
-
- while (1)
- {
- printf("Input: ");
-
- scanf("%s", input);
-
- send(sock, input, strlen(input) + 1, 0);
-
- n = recv(sock, buf, sizeof(buf), 0);
-
- if (n > 0)
- {
- printf("Receive data: %s\n", buf);
- }
- else
- {
- break;
- }
- }
-
- closesocket(sock);
-
- WSACleanup();
-
- return 0;
- }
server.c
-
- #include <iostream>
- #include <winsock2.h>
-
- #pragma warning(disable : 4996)
-
- int main()
- {
- SOCKET server = 0;
- struct sockaddr_in saddr = { 0 };
- SOCKET client = 0;
- struct sockaddr_in caddr = { 0 };
- int csize = 0;
- char buf[32] = { 0 };
- int r = 0;
-
- WSADATA wd = { 0 };
-
- if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
- {
- printf("startup error\n");
-
- return -1;
- }
-
- server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (server == INVALID_SOCKET)
- {
- printf("server socket error\n");
-
- return -1;
- }
-
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl(INADDR_ANY);
- saddr.sin_port = htons(8888);
-
- if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR)
- {
- printf("server bind error\n");
-
- return -1;
- }
-
- if (listen(server, 1) == SOCKET_ERROR)
- {
- printf("server listen error\n");
-
- return -1;
- }
-
- printf("start to accept\n");
-
- while (1)
- {
- csize = sizeof(caddr);
-
- client = accept(server, (struct sockaddr*)&caddr, &csize);
-
- if (client == INVALID_SOCKET)
- {
- printf("server accept error\n");
-
- return -1;
- }
-
- printf("client = %d\n", client);
-
- do
- {
- r = recv(client, buf, sizeof(buf), 0);
-
- if (r > 0)
- {
- if (strcmp("quit", buf) == 0)
- {
- break;
- }
- else
- {
- printf("Receive data: %s\n", buf);
-
- send(client, buf, strlen(buf) + 1, 0);
- }
- }
-
- } while (r > 0);
-
- closesocket(client);
- }
-
- closesocket(server);
-
- WSACleanup();
-
- return 0;
- }
程序运行结果如下:
select() 是 Linux 系统特有的吗?
Windows 中同样提供 select() 函数,且参数和 Linux 的版本完全相同
注意:Windows 中的 select() 函数,第一个参数没有任何意义 (仅为了兼容)
Windows 中的 select() 专门为套接字而设计
select-server.c
-
- #include <iostream>
- #include <winsock2.h>
-
- #pragma warning(disable : 4996)
-
- SOCKET server_handler(SOCKET server)
- {
- struct sockaddr_in addr = { 0 };
- int asize = sizeof(addr);
-
- return accept(server, (struct sockaddr*)&addr, &asize);
- }
-
- int client_handler(SOCKET client)
- {
- int ret = -1;
- char buf[32] = { 0 };
-
- ret = recv(client, buf, sizeof(buf) - 1, 0);
-
- printf("Receive: %s\n", buf);
-
- if (ret > 0)
- {
- buf[ret] = '0';
-
- if (strcmp(buf, "quit") != 0)
- {
- ret = send(client, buf, strlen(buf), 0);
- }
- else
- {
- ret = -1;
- }
- }
-
- return ret;
- }
-
- int main()
- {
- SOCKET server = 0;
- struct sockaddr_in saddr = { 0 };
- int num = 0;
- fd_set reads = { 0 };
- fd_set temps = { 0 };
- struct timeval timeout = { 0 };
-
- WSADATA wd = { 0 };
-
- if (WSAStartup(MAKEWORD(2, 2), &wd) != 0)
- {
- printf("startup error\n");
-
- return -1;
- }
-
- server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (server == INVALID_SOCKET)
- {
- printf("server socket error\n");
-
- return -1;
- }
-
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl(INADDR_ANY);
- saddr.sin_port = htons(8888);
-
- if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR)
- {
- printf("server bind error\n");
-
- return -1;
- }
-
- if (listen(server, 1) == SOCKET_ERROR)
- {
- printf("server listen error\n");
-
- return -1;
- }
-
- FD_ZERO(&reads);
- FD_SET(server, &reads);
-
- printf("start to accept\n");
-
- while (1)
- {
- timeout.tv_sec = 0;
- timeout.tv_usec = 10000;
-
- temps = reads;
-
- num = select(0, &temps, NULL, NULL, &timeout);
-
- if (num > 0)
- {
- for (int i = 0; i <= reads.fd_count; i++)
- {
- SOCKET sock = reads.fd_array[i];
-
- if (FD_ISSET(sock, &temps))
- {
- if (sock == server)
- {
- SOCKET client = server_handler(server);
-
- if (client != INVALID_SOCKET)
- {
- FD_SET(client, &reads);
-
- printf("accept client: %d\n", client);
- }
- }
- else
- {
- if (client_handler(sock) == -1)
- {
- FD_CLR(sock, &reads);
-
- closesocket(sock);
- }
- }
- }
- }
- }
- }
-
- closesocket(server);
-
- WSACleanup();
-
- return 0;
- }
Windows 下的 select() 函数,根据所监听文件描述符的个数遍历,相较于 Linux 的实现,遍历的次数更少,效率更高。
程序运行结果如下:
如何编写跨平台编译运行的网络程序?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。