C:2客户端和1个服务器中的UDP套接字编程

时间:2013-02-24 15:08:51

标签: c udp client

我是网络编程的新手。我有一个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;
}

1 个答案:

答案 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 /端口。这是你的应用程序问题,弄清楚它将如何获取该信息以及在何处存储该信息供以后使用。