c - 套接字编程(客户端-服务器 UDP)

标签 c sockets udp

我想构建一个客户端-服务器模型,对于连接到服务器的任意数量的客户端,服务器应该发送广播消息。下面是我实现的代码,它不会抛出任何错误,但我看不到服务器和客户端之间发生任何通信。请告诉我,代码中的问题出在哪里。

我想在客户端系统上查看从服务器传递的消息。

    /************* UDP SERVER CODE *******************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
  int udpSocket, nBytes, buflen;
  char buffer[1024];
  char string[1024];
  int portNum;
  struct sockaddr_in serverAddr, clientAddr;
  struct sockaddr_storage serverStorage;
  socklen_t addr_size, client_addr_size;
  int i;

  /*Create UDP socket*/
  udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
  portNum=atoi(argv[1]);
  /*Configure settings in address struct*/
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(5000);
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117");

  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /*Bind socket with address struct*/
  int bStatus=bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
   if (bStatus < 0) {
        printf("error binding on server's port number\n"); 
        exit(1);
  }     


  /*Initialize size variable to be used later on*/
  addr_size = sizeof serverStorage;

memset(&clientAddr, 0, sizeof(clientAddr));
  clientAddr.sin_family = AF_INET;
  clientAddr.sin_port = htons(portNum);  // this is where client is bound
  clientAddr.sin_addr.s_addr = inet_addr("192.168.1.114");

  while(1){
sprintf(buffer,"Hello Client");
  buflen=strlen(buffer);
  int bytesSent = sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&clientAddr, sizeof(clientAddr));
  if (bytesSent < 0) {
        printf("Error sending/ communicating with client\n");
        exit(1);
  }
  printf("%s\n",buffer);

/*
// ****************************************************

memset(buffer, 0, 1024);
buflen=65536;
recvfrom(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage, &addr_size);
printf("Received from server: %s\n",buffer);  

*/
}

  return 0;
}

下面是客户端代码:

     /************* UDP CLIENT CODE *******************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char *argv[]){
  int clientSocket, portNum, nBytes, buflen;
  char buffer[1024];
  char string[1024];
  struct sockaddr_in serverAddr,clientAddr;
  socklen_t addr_size;

  /*Create UDP socket*/
  clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
 portNum = atoi(argv[1]);
  /*Configure settings in address struct*/
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(portNum);
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117");

//  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  
memset(&serverAddr,0,sizeof(serverAddr));


// binding 
bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr));


  /*Initialize size variable to be used later on*/
  addr_size = sizeof serverAddr;

  while(1){

memset(buffer, 0, 1024);
buflen=65536;
recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);
//recvfrom(clientSocket,buffer,buflen,0,NULL,NULL);
printf("Received from server: %s\n",buffer);

/*
//********************************************************************

sprintf(buffer,"Hello Client");    
 buflen=strlen(buffer);
 sendto(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr,addr_size);
 printf("%s\n",buffer);
*/
}

return 0;
}

最佳答案

在较高层面上,有一些事情需要解决。鉴于帖子中的代码有一个服务器发起与客户端的通信,需要修改以下行(以及这些的相关代码)

在服务器端:

  sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage,addr_size);

本质上,这里发生的事情是 udpSocket 绑定(bind)到 serverAddr,并且我们正在尝试发送到 serverStorage(最后第二个参数)。这里的问题是 serverStorage 没有绑定(bind)到任何东西。基本上sendto有源权但没有目的地。

在客户端:

recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);

clientSocket 没有绑定(bind)到任何东西,因此系统会选择一个随机端口来监听。在 recvfrom 调用中,第二个最后一个参数捕获另一端的地址详细信息。虽然在代码中您已将其绑定(bind)到服务器的 IP 和端口,但它没有任何效果,因为它是由 recvfrom 调用填充并返回的。

我建议让事情在这里发挥作用(您可以添加详细信息,但已经根据您发布的内容制定了框架)

server_initiating_with_client.c

    //...
    int udpSocket, nBytes, buflen;
    char buffer[1024];
    int portNum;
    struct sockaddr_in serverAddr, clientAddr;
    struct sockaddr_storage serverStorage;
    socklen_t addr_size, client_addr_size;

    /*Create UDP socket*/
    udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    portNum=atoi(argv[1]);
    /*Configure settings in address struct*/
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(5000);   // Making sure server has a unique port number
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    /*Bind socket with address struct*/
    int bStatus = bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
    if (bStatus < 0) {
        printf("error binding on server's port number\n");
        exit(1);
    }

    /*Initialize size variable to be used later on*/
    addr_size = sizeof serverStorage;

    /* Because server is initiating the communication here one needs to set the
     * clientAddr and needs to know the port number of the client
     */
    memset(&clientAddr, 0, sizeof(clientAddr));
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_port = htons(portNum);
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    while(1){
        sprintf(buffer,"Hello Client");   
        buflen=strlen(buffer);
        int bytesSent = sendto(udpSocket,buffer,buflen, 0,
            (struct sockaddr *)&clientAddr, 
            sizeof(clientAddr));
        if (bytesSent < 0) {
            printf("Error sending/ communicating with client\n");
            exit(1);
        }
            printf("Done sending %s\n", buffer);
                sleep(1);
    }
    ..

在客户端,类似的事情

    //..
    int clientSocket, portNum, nBytes, buflen;
    char buffer[1024];
    struct sockaddr_in serverAddr;
    struct sockaddr_in clientAddr;
    socklen_t addr_size;

    /*Create UDP socket*/
    clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
    portNum = atoi(argv[1]);
    /*Configure settings in address struct*/
    memset(&clientAddr, 0, sizeof(clientAddr));
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_port = htons(portNum);
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    memset(&serverAddr, 0, sizeof(serverAddr));


    /*Bind on client side as well because you are specifically sending something over
    * to the client. Usually the server will know where to talk back to the client
    * but in your example because of the reversed semantics this will be needed
    */

    bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr));

    /*Initialize size variable to be used later on*/
    addr_size = sizeof serverAddr;

    while(1){
        memset(buffer, 0, 1024);
        buflen=65536;
        recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);
        printf("Received from server: %s\n",buffer);
        sleep(1);
    }
    return 0;

如果将通信从客户端反转到服务器,则可以简化代码,从而消除客户端对固定端口号的需要。

关于c - 套接字编程(客户端-服务器 UDP),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42142473/

相关文章:

c - 在标准输入上使用 grep

windows-services - 如何知道哪个本地应用程序连接到我的套接字(Windows)

bash - 使 socat 逐行写入(TCP 或 UNIX)套接字以收集日志

c - 使用 va_list 和 va_arg 实现子函数

c - 在内存中压缩数据膨胀

c++ - 如何优化指针间接层

java - Java 中的套接字和流

networking - 我可以在受控环境中忽略 UDP 缺乏可靠性功能吗?

udp - 使用 Mathematica 连接到 UDP 数据流

c++ - 安全 UDP 套接字编程