单服务器,多客户端UDP应用程序在C (Winsock)



我已经创建了单个服务器和单个客户端回声应用程序。它适用于单个服务器和单个客户机。但是现在我想通过为单个服务器处理多个客户机来使它更实用。我偶然发现在服务器端使用listen()函数来处理多个客户端连接的想法,但后来我知道listen只用于TCP。请帮我一下。下面是我的单个服务器和单个客户端的功能代码。帮助我如何修改它,使其成为一个单服务器多客户端应用程序。

服务器:

#define PORT 8888   //The port on which to listen for incoming data
int main()
{
SOCKET s;
struct sockaddr_in serverSocket, clientSocket;
char receiveBuffer[1000];
//int receiveBufferLength=1000;
int clientSocketLength;
int recv_len;
clientSocketLength = sizeof(clientSocket) ;
WSADATA wsa; 
//Initialise winsock
printf("nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
  printf("Failed. Error Code : %d",WSAGetLastError());
    exit(EXIT_FAILURE);
}
printf("Socket Initialised.n");
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
{
    printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.n");   
//Prepare the sockaddr_in structure
serverSocket.sin_family = AF_INET;
serverSocket.sin_addr.s_addr = INADDR_ANY;
serverSocket.sin_port = htons( PORT );
//Bind
if( bind(s ,(struct sockaddr *)&serverSocket , sizeof(serverSocket)) == SOCKET_ERROR)
{
    printf("nBind failed with error code : %d" , WSAGetLastError());
    exit(EXIT_FAILURE);
}
printf("Bind donenn");
//keep listening for data
while(1)
{
    printf("ntttWaiting for data...n");
    fflush(stdout);
    //receiveBuffer[2000]=NULL;
    if((recv_len = recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &clientSocket, &clientSocketLength)) == SOCKET_ERROR)
    {
        printf("nnrecvfrom() failed with error code : %d" , WSAGetLastError());
        //exit(EXIT_FAILURE);
        while(1);
    }
    //print details of the client/peer and the data received
    printf("nnReceived packet from %s:%dn", inet_ntoa(clientSocket.sin_addr), ntohs(clientSocket.sin_port));
    printf("nClient Says: " );
        printf(receiveBuffer,recv_len);

    //now reply the client with the same data
    if (sendto(s, receiveBuffer, recv_len, 0, (struct sockaddr*) &clientSocket, clientSocketLength) == SOCKET_ERROR)
    {
        printf("nsendto() failed with error code : %d" , WSAGetLastError());
       // exit(EXIT_FAILURE);
        while(1);
    }
    else
        printf("nMessage Sent Back to Client");
}
closesocket(s);
WSACleanup();
return 0;
}
客户:

#define PORT 8888   //The port on which to listen for incoming data
#define SERVER "10.0.1.25"  //ip address of udp server
//#define PORT 8888   //The port on which to listen for incoming data
int main(void)
{
struct sockaddr_in connectedSocket;
int s;
int length=sizeof(connectedSocket);
char receiveBuffer[1000];
char message[1000];
//clear the buffer by filling null, it might have previously received data
memset(receiveBuffer,'', 1000);
WSADATA wsa;
//Initialise winsock
printf("nInitialising Winsock...n");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
    printf("nFailed. Error Code : %d",WSAGetLastError());
    exit(EXIT_FAILURE);
}
printf("n.........Initialised.n");

//create socket
if ( (s=socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR)
{
    printf("nnsocket() failed with error code : %d" , WSAGetLastError());
    exit(EXIT_FAILURE);
}

//setup address structure
memset((char *) &connectedSocket, 0, sizeof(connectedSocket));
connectedSocket.sin_family = AF_INET;
connectedSocket.sin_port = htons(PORT);
 //connectedSocket.sin_port = INADDR_BROADCAST;
connectedSocket.sin_addr.S_un.S_addr = inet_addr(SERVER);
while(1)
{
    printf("nnnEnter message : ");
    gets(message);
  //send the message
    if (sendto(s, message,sizeof(message) , 0 , (struct sockaddr *) &connectedSocket, sizeof(connectedSocket)) == SOCKET_ERROR)
    {
        printf("nsendto() failed with error code : %d" , WSAGetLastError());
        exit(EXIT_FAILURE);
    }
        printf("nMessage Successfully sent to Server");
      // fflush(stdout);
    if (recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &connectedSocket,&length) == SOCKET_ERROR)
    {
       printf("nrecvfrom() failed with error code : %d" , WSAGetLastError());
       exit(EXIT_FAILURE);
    }
    printf("nServer Says : ");
    printf(receiveBuffer,sizeof(receiveBuffer));
}
closesocket(s);
WSACleanup();
return 0;
}

让我为你解释一些可能让你困惑的事情。

首先,在您的服务器中,即使您想要广播,也需要将serverSocket.sin_addr.s_addr设置为INADDR_ANY。你不想让它变成INADDR_BROADCAST。这是简单地告诉服务器绑定在任何 IP地址,你的计算机有,因为一台计算机可以有多个IP。你做得对。

但是如何从服务器进行广播呢?您需要像这样使用setsockoptSO_BROADCAST参数…

int options = 1;
if ((setsockopt(s, SOL_SOCKET, SO_BROADCAST,(char *)&options,sizeof(options))) < 0){
    printf("%d",WSAGetLastError());
}
这将使您的服务器侦听广播,但是您如何发送广播呢?在调用sendto函数之前,需要在sockaddr结构体的s_addr字段中设置INADDR_BROADCAST
clientSocket.sin_addr.s_addr = INADDR_BROADCAST;

然后使用sendtoclientSocket将您的消息发送回来。

第二,在客户端代码中,根据应用程序的不同,有两个选项。

  1. 如果你想让你的客户端首先发送消息到服务器(直接没有广播),那么你做得对,通过设置inet_addr(SERVER),所以客户端只发送消息到你的服务器。

  2. 但是,如果你想让客户端广播消息,那么你需要在你的客户端再次使用setsockopt,就像在你的服务器中一样,并将connectSocket结构中的地址设置为INADDR_BROADCAST

最后,如果你能告诉我们你在这里想要完成什么,那就更好了。如果您希望客户端首先连接到服务器,然后服务器向其他客户端宣布客户端,那么您可能会采用TCP而不是UDP。

最新更新