作为一个包围我的头围绕udp套接字的尝试,我试图将代码从本教程页面
http://www.linuxhowtos.org/C_C++/socket.htm移植到winsock(运行在win 8,如果重要). [下面的直接链接]
代码当前编译并运行,但是我从来没有收到数据包,这两个程序只是等待并阻止recvfrom().我不断有这个同样的问题(例如,使用这个代码https://stackoverflow.com/a/679529/873217的修改版本,包括一个recvfrom()调用,并用这个代码C++ problem with Datagram (UDP)winsocket to sendto and recvfrom on the same socket through the loopback adapter进行更改).我想我正在做一些简单和根本的错误;但我无法自己找到它.希望有更多经验的人可以为我解决这个问题.谢谢.
补充笔记:
我正在运行服务器exe然后客户端exe在同一台计算机上.它被连接到互联网.我也尝试使用一个解析到我的IP地址的域名.我也尝试禁用防火墙,尽管我允许这两个程序完全访问.
直接链接到原始客户端和服务器代码:
http://www.linuxhowtos.org/data/6/client_udp.c
http://www.linuxhowtos.org/data/6/server_udp.c
我目前的尝试:
两者都链接到libws2_32.a
客户端代码:
#include <stdio.h> #include <winsock2.h> #include <string.h> void error(const char *); int main() { WSAData data; WSAStartup( MAKEWORD( 2,2 ),&data ); int sock,n; int length; struct sockaddr_in server,from; struct hostent *hp; char buffer[256]; unsigned short serverPort = 27072; sock = socket(AF_INET,SOCK_DGRAM,0); if (sock < 0) error("socket"); server.sin_family = AF_INET; hp = gethostbyname("localhost");//have also tried my url if (hp==0) error("Unknown host"); memmove((char *)hp->h_addr,(char *)&server.sin_addr,hp->h_length); server.sin_port = htons(serverPort); length = sizeof(struct sockaddr_in); printf("Please enter the message: "); memset(buffer,256); fgets(buffer,255,stdin); n = sendto (sock,buffer,strlen(buffer),(const struct sockaddr *)&server,length); if (n < 0) error("Sendto"); printf("sent %i bytes\n",n); n = recvfrom(sock,256,(struct sockaddr *)&server,&length); if (n < 0) error("recvfrom"); //write(1,"Got an ack: ",12); //write(1,n); printf("Got msg: %s\n",buffer); closesocket(sock); WSACleanup(); return(0); } void error(const char *msg) { perror(msg); exit(0); }
服务器代码:
#include <stdio.h> #include <winsock2.h> #include <string.h> void error(const char *); int main() { WSAData data; WSAStartup( MAKEWORD( 2,length,n; int fromlen; struct sockaddr_in server; struct sockaddr_in from; char buf[1024]; unsigned short serverPort = 27072; sock=socket(AF_INET,0); if (sock < 0) error("opening socket"); length = sizeof(server); memset(&server,length); server.sin_family = AF_INET; server.sin_addr.s_addr=INADDR_ANY; server.sin_port=htons(serverPort); if (bind(sock,length)<0) error ("binding"); fromlen = sizeof(struct sockaddr_in); while(1) { n = recvfrom(sock,buf,1024,(struct sockaddr *)&from,&fromlen); if (n<0) error("recvfrom"); //write(1,"Received a datagram: ",21); //write(1,n); printf("Received a datagram: %s",buf); n = sendto(sock,"Got your message\n",17,fromlen); if (n<0)error("sendto"); } closesocket(sock); WSACleanup(); return 0; } void error (const char *msg) { perror(msg); exit(0); }
解决方法
以下UDP测试应用程序在我的设置 – Windows 7,VS 2013上正常工作.
我创建了一些轻量级的包装类来进行资源管理,并将错误代码转换为异常.这使得客户端和服务器代码更容易阅读.请务必先运行服务器.
Network.h
#include <WinSock2.h> #include <WS2tcpip.h> #include <system_error> #include <string> #include <iostream> #pragma once class WSASession { public: WSASession() { int ret = WSAStartup(MAKEWORD(2,2),&data); if (ret != 0) throw std::system_error(WSAGetLastError(),std::system_category(),"WSAStartup Failed"); } ~WSASession() { WSACleanup(); } private: WSAData data; }; class UDPSocket { public: UDPSocket() { sock = socket(AF_INET,IPPROTO_UDP); if (sock == INVALID_SOCKET) throw std::system_error(WSAGetLastError(),"Error opening socket"); } ~UDPSocket() { closesocket(sock); } void SendTo(const std::string& address,unsigned short port,const char* buffer,int len,int flags = 0) { sockaddr_in add; add.sin_family = AF_INET; add.sin_addr.s_addr = inet_addr(address.c_str()); add.sin_port = htons(port); int ret = sendto(sock,len,flags,reinterpret_cast<SOCKADDR *>(&add),sizeof(add)); if (ret < 0) throw std::system_error(WSAGetLastError(),"sendto Failed"); } void SendTo(sockaddr_in& address,int flags = 0) { int ret = sendto(sock,reinterpret_cast<SOCKADDR *>(&address),sizeof(address)); if (ret < 0) throw std::system_error(WSAGetLastError(),"sendto Failed"); } sockaddr_in RecvFrom(char* buffer,int flags = 0) { sockaddr_in from; int size = sizeof(from); int ret = recvfrom(sock,reinterpret_cast<SOCKADDR *>(&from),&size); if (ret < 0) throw std::system_error(WSAGetLastError(),"recvfrom Failed"); // make the buffer zero terminated buffer[ret] = 0; return from; } void Bind(unsigned short port) { sockaddr_in add; add.sin_family = AF_INET; add.sin_addr.s_addr = htonl(INADDR_ANY); add.sin_port = htons(port); int ret = bind(sock,"Bind Failed"); } private: SOCKET sock; };
服务器
#include "Network.h" int main() { try { WSASession Session; UDPSocket Socket; char buffer[100]; Socket.Bind(100); while (1) { sockaddr_in add = Socket.RecvFrom(buffer,sizeof(buffer)); std::string input(buffer); std::reverse(std::begin(input),std::end(input)); Socket.SendTo(add,input.c_str(),input.size()); } } catch (std::system_error& e) { std::cout << e.what(); } }
客户
#include "Network.h" int main() { try { WSASession Session; UDPSocket Socket; std::string data = "hello world"; char buffer[100]; Socket.SendTo("127.0.0.1",100,data.c_str(),data.size()); Socket.RecvFrom(buffer,100); std::cout << buffer; } catch (std::exception &ex) { std::cout << ex.what(); } char c; std::cin >> c; }