本文用于记录win操作系统,C++语言,socket,udp通信
服务端流程首先要加载套接字库
- 创建套接字
- 服务端地址
- bind 套接字与地址绑定
- recvfrom 等待并接收数据
- sendto 发送数据
- 资源关闭
// udpsrv.cpp #include客户端流程#include #include #include #pragma comment(lib,"ws2_32.lib") int main() { WORD wVersionRequested;//unsigned short WSADATA wsaData;//这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据 int err; wVersionRequested = MAKEWORd(1,1); //WSAStartup就是为了向操作系统说明,我们要用哪个库文件,让该库文件与当前的应用程序绑定,从而就可以调用该版本的socket的各种函数了 err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)//低字节为主版本,高字节为副版本 { WSACleanup(); return -1; } //.......以上为准备环境....以下为具体服务端udp通讯流程.......... std::cout << "server is operating!nn"; //1.创建套接字 SOCKET socketSrv = socket(AF_INET, SOCK_DGRAM, 0); //2.服务端地址 SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", (void *)&addrSrv.sin_addr.S_un.S_addr); addrSrv.sin_port = htons(6000); //3.套接字绑定 bind(socketSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); SOCKADDR_IN addrClient;//用来接收客户端地址信息 char ClientIP[20]; int len = sizeof(SOCKADDR); char recvBuf[100]; char sendBuf[100]; char tempBuf[100]; while (1) { //4.等待并接收数据 recvfrom(socketSrv, recvBuf, 100, 0, (SOCKADDR*)&addrClient, &len); if ('q' == recvBuf[0]) { sendto(socketSrv, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrClient, len); std::cout << "chat end!nn"; break; } inet_ntop(AF_INET, (void *)&addrClient.sin_addr, ClientIP, 16); sprintf_s(tempBuf, "%s say : %s", ClientIP, recvBuf); printf("%sn",tempBuf); //5.发送数据 std::cout << "Please input data:"; gets_s(sendBuf); sendto(socketSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrClient, len); } //6.关闭资源 closesocket(socketSrv); WSACleanup(); return 0; }
首先要加载套接字库
- 创建用于监听的套接字
- 确定服务端通讯地址信息
- sendto 发送数据
- recvfrom 等待并接收数据
- 资源关闭
// udpclient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include遇到的问题#include #include #include #pragma comment(lib,"ws2_32.lib") int main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORd(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || //低字节为主版本 HIBYTE(wsaData.wVersion) != 1) //高字节为副版本 { WSACleanup(); return -1; } printf("Client is operating!nn"); //1.创建用于监听的套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); //2.确定服务端通讯地址信息 sockaddr_in addrSrv; inet_pton(AF_INET, "127.0.0.1", (void *)&addrSrv.sin_addr.S_un.S_addr); //addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//输入你想通信的她(此处是本机内部) addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); int len = sizeof(SOCKADDR); char recvBuf[100]; //收 char sendBuf[100]; //发 char tempBuf[100]; //存储中间信息数据 while (1) { printf("Please input data: "); gets_s(sendBuf); //3.发送数据 sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrSrv, len); //4.等待数据 recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR*)&addrSrv, &len); if ('q' == recvBuf[0]) { sendto(sockSrv, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrSrv, len); printf("Chat end!n"); break; } sprintf_s(tempBuf, "%s say : %s", "server", recvBuf); printf("%sn", tempBuf); } closesocket(sockSrv); WSACleanup(); return 0; }
-
错误:error C4996: ‘inet_addr’: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
原因:在VS2013以后的版本中,增加了inet_pton()、InetPton()之类的新函数,用于IP地址在“点分十进制”和“二进制整数”之间转换,并且能够处理ipv4和ipv6。而inet_addr是老函数,高版本VS在编译时默认使用了新函数,所以会报该错误。
解决办法:
inet_pton(AF_INET, "127.0.0.1", (void *)&addrSrv.sin_addr.S_un.S_addr); //addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//输入你想通信的她(此处是本机内部) -
错误:C4996 ‘inet_ntoa’: Use inet_ntop() or InetNtop() instead or define
原因:同上
解决办法:
inet_ntop(AF_INET, (void *)&addrClient.sin_addr, ClientIP, 16);
-
错误LNK2019: 无法解析的外部符号 _WSAStartup@8,该符号在函数 _main 中被引用
原因:编译器没有链接到我们想要的头文件运行库
解决办法:#pragam 编译器指令,指示编译器链接到
#pragma comment(lib,"ws2_32.lib")问题总结
第一类问题是主机字节序列与网络字节序列转换函数的版本问题
第二类是编译问题
程序运行效果图


