我是网络编程的新手。我有一个UDP客户端/服务器,它以较低或大写的形式向服务器发送消息。服务器接收消息并通过交换机案例将其中继。我无法弄清楚如何将其转发回第一个客户端,将其发送到client2。继承我的代码。
服务器:
/*
Simple udp server
*/
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_me, si_other, si_other2;
int s, i, slen = sizeof(si_other) , recv_len;
char buf[BUFLEN];
//create a UDP socket
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
die("socket");
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
//bind socket to port
if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
die("bind");
}
//keep listening for data
while(1)
{
printf("Waiting for data...");
fflush(stdout);
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1) // read datagram from server socket
{
die("recvfrom()");
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); printf("Data: %s\n" , buf);
//now reply to server socket/the client with the same data
if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1)
{
die("sendto()");
}
}
close(s);
return 0;
}
客户:
/*
Simple udp client
*/
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>
#define SERVER "192.x.x.x"
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to send data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_other;
int s, s2, i, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) // create a client socket
{
die("socket");
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SERVER , &si_other.sin_addr) == 0) // Create datagram with server IP and port.
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
while(1)
{
printf("Enter message : ");
gets(message);
int a;
char message2[BUFLEN];
for(a=0;a<=BUFLEN-1;a++)
{
if(message[a] >= 97 && message[a] <= 122)
message2[a] = toupper(message[a]);
else
message2[a] = tolower(message[a]);
}
if (sendto(s, message2, strlen(message2) , 0 , (struct sockaddr *) &si_other, slen)==-1)
{
die("sendto()");
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1) // read datagram from client socket
{
die("recvfrom()");
}
puts(buf);
}
close(s);
return 0;
}
答案 0 :(得分:6)
由于这有21K的视图没有明确的答案,而且它是对UDP编码的基本理解。我会给它一些爱。
正如评论中已提到的:在您的服务器代码中,您使用以下命令从客户端收到消息:
recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen))
此函数的结果是消息数据将写入buf
,并且发送消息的套接字的IP地址和端口号将填入si_other
(必须是输入struct sockaddr_in
)。
那么,当您使用以下方式发送回复时:
sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen)
由于您作为si_other
的目标地址传递的sendto
包含您收到的最后一条消息的IP /端口,因此响应将始终返回到最后一条消息的发送方你得到了。在许多服务器应用程序中,这是一种非常常见的情况:您从某个地方收到请求,然后将响应发送回同一个地方。
如果您希望消息转到其他地方,而不是发送请求的进程,那么您需要创建一个不同的struct sockaddr_in变量,其中包含您希望消息的IP地址和端口。
在您的客户端代码中,您已经拥有了执行此操作的代码,例如(清理了一下):
struct sockaddr_in si_client2;
memset((char *) &si_client2, 0, sizeof(si_client2));
si_client2.sin_family = AF_INET;
si_client2.sin_port = htons(CLIENT2_PORT);
if(inet_aton(CLIENT2_HOST, &si_client2.sin_addr) == 0)
perror("inet_aton");
现在,如果你在sendto()中使用si_client2,数据包将转到该客户端。
因为它是UDP,所以无法保证交付。如果有一个进程在该IP地址上侦听UDP,在该端口号上,则(如果没有发生网络错误)它将获得该消息。如果没有,什么都不会发生..你的信息消失在虚空中。
请记住,如果客户端1和客户端2都在同一台计算机上运行,则需要使用不同的端口号,因为每个目标(无论是客户端角色还是服务器角色)都必须具有唯一的IP组合PORT。
现在,在现实生活中,服务器很少会提前知道其客户端的IP和PORT。通常客户端不会使用固定端口号,而是使用“临时端口”..端口号操作系统在运行时分配的。然而,客户端通常会配置服务器的IP和端口。
所以,在大多数情况下,你会在服务器中有一些代码来保存客户端地址列表。也许一个简单的消息传递服务会保留最后100个客户端列表中的消息......但是这是怎么回事实际上完成将取决于应用程序的需求。对于像这样的简单练习,您可以像我说的那样对地址进行硬编码......
最重要的是,要将UDP数据包发送到特定目的地,发件人必须知道该特定目的地的IP和PORT。知道这一点的唯一方法是要么拥有一些配置数据,要么为某人(例如目的地)提前发送数据包,让您知道它的存在。请记住,使用UDP套接字,您可以从任何地方获取消息,并且您将获得ip / port以及消息。如果您需要发送消息,则需要知道要将其发送到的位置的IP /端口。这是你的应用程序问题,弄清楚它将如何获取该信息以及在何处存储该信息供以后使用。