我目前有问题在服务器和客户端之间传递消息。 据我所知,我正确遵循了由Beej的Socket编程教程概述的套接字编程的最佳实践。
当我运行这两个进程时,recv()系统调用返回-1(错误),而不是接收到的字节数。 当试图输出buf时,还有一堆gobbledygook字符。 这是有道理的,因为错误。
我想知道是否有人可以引导我正确的方向,为什么我有问题与recv()? 以下是相关的代码片段。
服务器:
struct sockaddr_storage their_addr; socklen_t addr_size; int sockfd, newfd, byte_count, status; char buf[512]; struct addrinfo hints, *res; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; // get address info, print stuff if error if((status = getaddrinfo("nunki.usc.edu", "21957", &hints, &res)) !=0){ fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); exit(1); } // make a socket: if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ cout << "socket fail" << endl; } // bind the socket to the port bind(sockfd, res->ai_addr, res->ai_addrlen); // required output cout << "Phase1: Login server has TCP port number " << "21957 " << "and IP address " << getIPfromHost("nunki.usc.edu") << endl; // listen for incoming connections listen(sockfd, 10); cout << "after listen" << endl; // halt until receipt addr_size = sizeof(their_addr); newfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); cout << "after accept" << endl; // Now that we're connected, we can receive some data byte_count = recv(sockfd, buf, sizeof buf, 0); printf("recv()'d %d bytes of data in buf\n", byte_count); printf("Msg is %s\n", buf);
客户:
struct addrinfo hints, *res; int sockfd; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; getaddrinfo("nunki.usc.edu", "21957", &hints, &res); // make a socket: if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ cout << "socket fail" << endl; } // attempt connection to port if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){ cout << "connect fail" << endl; } // send message to server cout << "sockfd " << sockfd << endl; int byte_count = send(sockfd, "Hello", 5, 0); cout << byte_count << endl;
以下是服务器的输出:
Phase1: Login server has TCP port number 21957 and IP address 68.181.201.3 after listen after accept recv()'d -1 bytes of data in buf Msg is ÿhÿ?sÈ Glæ
以下是客户端的输出:
sockfd 4 5
你在错误的socket上调用recv
。 你需要recv
在newfd
:
byte_count = recv(newfd, buf, sizeof buf, 0); /* newfd instead of sockfd. */
既然这样,
据我所知,我正确地遵循套接字编程的最佳实践
我完全不同意。
listen
, bind
, getaddrinfo
等 strerror
或perror
你想recv()使用从accept()返回的套接字
byte_count = recv(newfd, buf, sizeof buf, 0);
也许我不应该写这个答案,而是作为一个评论。 不过,恕我直言,你使用getaddrinfo()
似乎是错误的。
在客户端,它应该被调用,然后遍历结果,直到可以建立连接。
所以
struct addrinfo * r2 sockfd = -1; for (r2=res; r2; r2=r2->ai_next) { // make a socket: if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ continue; // next result } // attempt connection to port if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){ close(sockfd); sockfd = -1; continue; } } if (sockfd == -1) { // do error handling }
这样,您可以检查所有可能的连接。
在服务器端,使用getaddrinfo()
是非常不寻常的。 通常情况下,您将创建一个IPv6套接字并使其能够侦听IPv4,并使用setsockopt()
来取消设置IPV6_V6ONLY
标志。 通过这种方式,套接字同时监听IPv6和IPv4。 (唉,不在WIndows XP AFAIK。)
sockfd
仅用于监听客户端, newfd
用于数据传输。