2013-02-24 46 views
3

对于网络编程我很新颖。我有一个UDP客户端/服务器,以大写或小写形式向服务器发送消息。服务器收到该消息并将其中继交换机箱。我无法弄清楚我将如何将其转发回第一个客户端,并将其发送给client2。继承我的代码。C:2客户端和1服务器中的UDP套接字编程

服务器:

/* 
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; 
} 
+1

由于UDP不是面向连接的,所以实际上并没有客户端。您必须等到客户端与服务器通信,然后跟踪客户端。 – 2013-02-24 15:14:54

+1

UDP没有客户端。因为它是无连接的,所以服务器上的你要跟踪你的客户和发送给谁。 – Linuxios 2013-02-24 15:15:53

+1

您的代码将回复发回给它已收到数据的相同'si_other'。尝试先让两个客户端'si_other',然后你可以区分。 – hiteshradia 2013-02-24 15:23:42

回答

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变量,它包含你希望消息去的地址和端口。

而在你的客户端代码,您已经有这样做,例如,(清理位)代码:

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和端口。通常客户端不会使用固定端口号,而是使用“临时端口”端口操作系统在运行时分配的数字。而客户端通常会配置服务器的IP和端口。

因此,在大多数情况下,您将在服务器中保留一些客户端地址列表中的代码。也许一个简单的消息服务会保留最近100个获得消息的客户端列表......但实际上如何实现将取决于应用程序的需求。对于这样一个简单的练习,你可以像我刚才所说的那样对地址进行硬编码...

底线是,要将UDP数据包发送到特定的目的地,发件人必须知道IP和PORT该特定目的地。而要知道这一点的唯一方法是要么有一些配置数据,要么有人(如目的地)提前发送数据包,让你知道它的存在。请记住,使用UDP套接字,您可以从任何地方获得消息,并且您将获得IP /端口以及消息。如果你需要发送消息,你需要知道你想发送它的IP /端口。这是您的应用程序问题,要弄清楚它将如何获取该信息以及将信息存储在何处以供以后使用。