我正在尝试实现一个echo客户端。使用sendto()的客户端正在传输消息,服务器正在接收n显示它。但是服务器没有发送消息(回显)。这是服务器和客户端的代码。谁能帮我这个?
服务器:
char msg[100]="";
int conn_sock,n;
struct sockaddr_in server_addr,client_addr;
conn_sock=socket(AF_INET,SOCK_DGRAM,0);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(1234);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
err=bind(conn_sock, (struct sockaddr *)&server_addr,sizeof(server_addr));
n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr);
n=sendto(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,sizeof(client_addr));
在recvfrom中,n的值是字节数。但是在sendto()中,n的值是-1
客户端:
char msg[100];
int conn_sock,n,err;
struct sockaddr_in server_addr;
conn_sock=socket(AF_INET,SOCK_DGRAM,0);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(1234);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
cin>>msg;
n=sendto(conn_sock,msg,strlen(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr);
recvfrom()未从服务器接收任何数据。
答案 0 :(得分:1)
这两行都错了:
// In the server
n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr);
// In the client
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr);
recvfrom()
的最后两个参数应该指向两个单独的变量。其中一个接收另一个对等网络地址,另一个接收该网络地址的长度。您将相同的指针值传递给两者都意味着地址长度会覆盖地址数据的前几个字节,从而破坏它并导致不良。
这里是服务器应该如何工作,将长度接收到一个单独的变量中:
struct sockaddr_storage client_addr;
socklen_t client_addr_len = sizeof(client_addr); // This is an in+out parameter
n=recvfrom(..., (struct sockaddr *)&client_addr, &client_addr_len);
n=sendto(..., (struct sockaddr *)&client_addr, client_addr_len);
请注意,我使用sockaddr_storage
代替sockaddr_in
。保证sockaddr_storage
大到足以容纳支持的地址族的任何有效套接字地址类型,以便此代码与IPv6向前兼容。
同样,这里是客户应该如何运作的:
n=sendto(..., &server_addr, sizeof(server_addr));
do
{
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
n=recvfrom(..., (struct sockaddr *)&peer_addr, &peer_addr_len);
} while (!areSockAddrsEqual((struct sockaddr *)&server_addr, (struct sockaddr *)&peer_addr));
...
bool areSockAddrsEqual(struct sockaddr *addr1, struct sockaddr *addr2)
{
if (addr1->sa_family != addr2->sa_family)
return false;
switch (addr1->sa_family)
{
case AF_INET:
struct sockaddr_in *addr1_in = (struct sockaddr_in *)addr1;
struct sockaddr_in *addr2_in = (struct sockaddr_in *)addr2;
return (addr1_in->sin_port == addr2_in->sin_port &&
addr1_in->sin_addr.s_addr == addr2_in->sin_addr.s_addr);
...
// Other address families such as AF_INET6 left as an exercise
}
}
这里我们再次确保传递一个单独的socklen_t
指针来接收地址长度,然后我还添加了一个循环以确保我们收到的实际数据包是我们期望从目标服务器获得的数据包。如果我们收到一个不同的数据包(比如,由于另一个正好碰巧在错误的时间向我们发送数据包),我们会忽略它。
检查两个套接字地址是否相等有点粗糙,因为它取决于地址族,并且支持IPv4和IPv6都很棘手。