我有一个小程序,可以从服务器和客户端发送和接收数据,反之亦然。 一切正常,但我看不到双方收到的消息,它总是0字节。它没有给出任何编译错误但是没有按照我想要的方式工作。 你能不能看看我做错了什么? 感谢
//客户端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char* argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
char* hostname = "localhost";
char* server = "localhost";
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(hostname, "5000", &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 0;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to bind socket\n");
return 2;
}
char message[] = "hi";
if ((numbytes = send(sockfd, message, 2, 0)) == -1)
{
perror("client: send");
exit(1);
}
int numbytesRecv;
char buf[100];
if ((numbytesRecv = recv(sockfd, buf, 99, 0)) == -1)
{
perror("client: recv");
exit(1);
}
freeaddrinfo(servinfo);
printf("client: sent %d bytes to %s\n", numbytes, server);
printf("client: received %d bytes from %s\n", numbytesRecv, server);
buf[numbytesRecv] = '\0';
printf("client: message received is %s\n",buf);
close(sockfd);
return 0;
}
// server
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT "5000" // the port users will be connecting to
#define MAXBUFLEN 100
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfdTCP;
struct addrinfo hintsTCP, *servinfoTCP, *pTCP;
int rv;
int numbytes;
struct sockaddr_storage their_addr;
char buf[MAXBUFLEN];
size_t addr_len;
char s[INET6_ADDRSTRLEN];
memset(&hintsTCP, 0, sizeof hintsTCP);
hintsTCP.ai_family = AF_UNSPEC;
hintsTCP.ai_socktype = SOCK_STREAM;
hintsTCP.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, MYPORT, &hintsTCP, &servinfoTCP)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can for TCP socket
for(pTCP = servinfoTCP; pTCP != NULL; pTCP = pTCP->ai_next)
{
if ((sockfdTCP = socket(pTCP->ai_family, pTCP->ai_socktype,pTCP->ai_protocol)) == -1)
{
perror("listener: socket");
continue;
}
if (bind(sockfdTCP, pTCP->ai_addr, pTCP->ai_addrlen) == -1)
{
close(sockfdTCP);
perror("listener: bind");
continue;
}
break;
}
if (pTCP == NULL)
{
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfoTCP);
printf("listener: waiting to recvfrom...\n");
addr_len = sizeof their_addr;
const int BACKLOG = 10;
if (listen(sockfdTCP, BACKLOG) == -1) {
perror("listen");
exit(1);
}
socklen_t sin_size;
int new_fd;
sin_size = sizeof their_addr;
new_fd = accept(sockfdTCP, (struct sockaddr *)&their_addr, &sin_size);
printf("I am here\n");
if (new_fd == -1)
{
perror("accept");
}
if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1))
{
perror("recv");
exit(1);
}
char* msg = " hi i am server";
int numbytesSend;
if ((numbytesSend = send(new_fd, msg,strlen(msg), 0) == -1))
{
perror("recv");
exit(1);
}
inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
printf("listener: packet is %d bytes long\n", numbytes);
buf[numbytes] = '\0';
printf("listener: packet contains : %s\n", buf);
close(sockfdTCP);
close(new_fd);
return 0;
}
//输出客户端
./clientTCP
client: sent 2 bytes to localhost
client: received 0 bytes from localhost
client: message received is
//输出服务器
./serverTCP
listener: waiting to recvfrom...
I am here
server: got connection from 127.0.0.1
listener: packet is 0 bytes long
listener: packet contains :
答案 0 :(得分:7)
您的问题是服务器中的这一行:
if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1))
应该是:
if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0)) == -1)
这将允许正确分配numbytes,这允许
buf[numbytes] = '\0';
做你想做的事情并让我们
printf("listener: packet contains : %s\n", buf);
打印你想要的东西。
同样处理
if ((numbytesSend = send(new_fd, msg, strlen(msg), 0) == -1))
但该错误并未在示例程序中显示出来。
答案 1 :(得分:2)
自从我完成原始套接字编程以来已经有一段时间了,但我认为你的recv()
调用有些可疑。 IIRC,recv()
阻塞,直到它读取缓冲区的完整大小或连接已关闭。由于两端都没有发送足够的数据来填充缓冲区,并且套接字在recv()
调用之后才关闭,我认为您的客户端/服务器中的一个或两个应该挂起。既然他们没有,就会发生两件事之一。套接字配置为非阻塞模式,您需要将它们配置为阻止,或者某些东西正在关闭套接字。对不起,我不能提供比这更详细的帮助,但希望它会指出你正确的方向。您可能还想调查在套接字上使用的shutdown()
调用,以便在发送缓冲区中的所有数据之前不要关闭它们。不确定这是否与您的问题有关。
答案 2 :(得分:2)
编辑:我刚刚在OS X上测试过。您的代码适用于我。现在,我真的认为你必须有一些东西消耗你的字节。杀死你的流程并做:
$ netstat -na | grep 5000
查看是否有任何侦听端口5000的内容。如果是,则需要终止服务器。
另外,请确保超级服务器(inetd / xinetd)没有产生处理端口5000上的数据的东西。
答案 3 :(得分:1)
看起来你被Nagle's Algorithm咬了。尝试设置TCP_NODELAY以允许立即发送小数据包。
请注意,对于生产代码,您应该在决定禁用Nagle算法之前进行配置。