0

単一のサーバーと単一のクライアントのエコー アプリケーションを作成しました。単一のサーバーと単一のクライアントで正常に機能します。しかし今は、単一のサーバーに対して複数のクライアントを処理することで、より実用的にしたいと考えています。サーバー側で 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 done\n\n");

//keep listening for data

while(1)
{
    printf("\n\t\t\tWaiting for data...\n");
    fflush(stdout);
    //receiveBuffer[2000]=NULL;

    if((recv_len = recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &clientSocket, &clientSocketLength)) == SOCKET_ERROR)
    {
        printf("\n\nrecvfrom() failed with error code : %d" , WSAGetLastError());
        //exit(EXIT_FAILURE);
        while(1);
    }

    //print details of the client/peer and the data received
    printf("\n\nReceived packet from %s:%d\n", 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,'\0', 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("\n\nsocket() 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("\n\n\nEnter 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;

}
4

1 に答える 1

2

混乱するかもしれないいくつかのことを説明させてください。

まず、サーバーで、ブロードキャストする場合でもに設定serverSocket.sin_addr.s_addrする必要があります。INADDR_ANYあなたはそれを作りたくないINADDR_BROADCASTこれは、コンピュータが持っている任意のIPアドレスにバインドするようにサーバーに指示しているだけです。これは、1台のコンピュータが複数のIPを持つことができるためです。あなたが正しくやっている。

しかし、サーバーからどのようにブロードキャストできますか?このようなパラメータで使用setsockoptする必要があります...SO_BROADCAST

int options = 1;
if ((setsockopt(s, SOL_SOCKET, SO_BROADCAST,(char *)&options,sizeof(options))) < 0){
    printf("%d",WSAGetLastError());
}

これにより、サーバーはブロードキャストをリッスンしますが、ブロードキャストを送信するにはどうすればよいですか?関数を呼び出す前に、 sockaddr構造体INADDR_BROADCASTs_addrフィールドに設定する必要があります。sendto

clientSocket.sin_addr.s_addr = INADDR_BROADCAST;

次に、withを使用sendtoclientSocketてメッセージをボードキャストします。

次に、クライアントコードには、アプリケーションに応じて2つのオプションがあります。

  1. クライアントが最初にサーバーにメッセージを送信するようにしたい場合(ブロードキャストなしで直接)inet_addr(SERVER)、クライアントがサーバーにのみメッセージを送信するように設定することで、正しく実行しています。

  2. ただし、クライアントにメッセージをブロードキャストさせたい場合はsetsockopt、サーバーと同じようにクライアントで再度使用し、connectSocket構造内のアドレスをに設定する必要がありますINADDR_BROADCAST

最後に、ここで何を達成しようとしているのかを教えていただければ幸いです。クライアントが最初にサーバーに接続し、次にサーバーがクライアントを他のクライアントにアナウンスするようにしたい場合は、UDPの代わりにTCPを使用できます。

于 2013-03-12T09:18:38.220 に答える