2014-03-01 36 views
1

我有3个应用程序,一个服务器,2个客户端。我试图对此进行编程,以便我可以将来自客户端的登录请求发送到服务器,并请求查看有关其他客户端的信息。在一台服务器上接收多个客户端数据包

问题:我对所有3个应用程序使用相同的ip和端口号(全部在我的计算机上的3个visual studio应用程序上完成),否则我不认为它连接到服务器。这个可以吗?

当我尝试在服务器的while循环之外使用listen和accept时,它适用于一个客户端,但不适用于其他客户端。当我尝试在while循环内部放置listen和accept时,它适用于两个客户端,但不响应多个accept。我的问题是什么?

服务器

struct Users { 

int message; 
char userName[50]; 
char ipAddress[50]; 
int PortNumber; 
bool online; 

}; 

int main() { 

//Create users 
Users client[2]; 

client[0].PortNumber = 20000; 
client[0].online = false; 
sprintf(&client[0].userName[0], "Albert"); 
sprintf(&client[0].ipAddress[0], "127.0.0.1"); 

client[1].PortNumber = 20000; 
client[1].online = false; 
sprintf(&client[1].userName[0], "Monique"); 
sprintf(&client[1].ipAddress[0], "127.0.0.1"); 


//Set up all the connection stuff 
struct sockaddr_in SvrAddr; 
SOCKET WelcomeSocket, ConnectionSocket; 
int PortNumber = 20000; 
int result; 
char IPAddress[] = "127.0.0.1"; 
char RxBuffer[128]; 
char TxBuffer[128]; 


WORD wVersionRequested; 
WSADATA wsaData; 

wVersionRequested = MAKEWORD(2,2); //For Server 


if(WSAStartup(wVersionRequested, &wsaData) != 0) 
    return -1; 


//Setting up the welcome socket 
WelcomeSocket = socket(AF_INET, SOCK_STREAM, 0); 

//Setting up the sockaddr svraddr structure 
SvrAddr.sin_family = AF_INET; 
SvrAddr.sin_addr.s_addr = inet_addr(IPAddress); 
SvrAddr.sin_port = htons(PortNumber); 


//Bind 
bind(WelcomeSocket, (sockaddr*)&SvrAddr, sizeof(SvrAddr)); 

//listening 
//listen(WelcomeSocket, 5); 

//temp users 
Users temp; 
//ConnectionSocket = accept(WelcomeSocket, NULL, NULL); 
ConnectionSocket = SOCKET_ERROR; 

//while loop for the connection 
while (1) { 

    listen(WelcomeSocket, 5); 

    if ((ConnectionSocket = accept(WelcomeSocket, NULL, NULL)) == SOCKET_ERROR) 
    { 
     return -1; 
    } 

    else { 

    int n = recv(ConnectionSocket, RxBuffer, sizeof(RxBuffer), 0); 

    if (n == 0) 
     break; 


    memcpy(&temp, RxBuffer, sizeof(struct Users)); 

    //cout << temp.message << temp.userName << endl << endl; 

    //check which message type is being sent 
    switch(temp.message) { 

    //if message type 1 
    case 1 : 
     for (int i = 0; i < 2; i++) { 

      //if receieved username matches with any username in the database 
      if (strcmp(temp.userName, client[i].userName) == 0) { 

       //assign the recieved users information to the matched one in database 
       strcpy(client[i].userName, temp.userName); 
       client[i].online = true; 
       client[i].message = 2; 

       cout << "Username: " << client[i].userName << endl << "Online status: " << client[i].online << endl << endl; 

       //send the acknowledgement packet 
       send(ConnectionSocket, (char *)&client[i], sizeof(struct Users), 0); 
       //closesocket(ConnectionSocket); 
      } 

     } 
     break; 

    //if message type 3 
    case 3 : 

     cout << "User being searched for: " << temp.userName << endl << endl; 
     for (int i = 0; i < 2; i++) { 

      //if receieved username matches with any username in the database 
      if (strcmp(temp.userName, client[i].userName) == 0) { 
       client[i].message = 4; 
       //send the acknowledgement packet 
       send(ConnectionSocket, (char *)&client[i], sizeof(struct Users), 0); 
       //closesocket(ConnectionSocket); 
      } 

     } 
     break; 

    default : 
     break; 

    } 

} 

} 

closesocket(ConnectionSocket); 
WSACleanup(); 
} 

客户端(两者相同)

struct Users { 

int message; 
char userName[50]; 
char ipAddress[50]; 
int PortNumber; 
bool online; 

}; 


int main() { 

struct sockaddr_in SvrAddr; 
SOCKET ClientSocket; 
int PortNumber = 20000; 
char IPAddress[] = "127.0.0.1"; 
//char message[] = "Hello this is the client."; 
char RxBuffer[128]; 

WORD wVersionRequested; 
WSADATA wsaData; 

wVersionRequested = MAKEWORD(2,3); //For Client 

if(WSAStartup(wVersionRequested, &wsaData) != 0) 
    return -1; 


ClientSocket = socket(AF_INET, SOCK_STREAM, 0); 

SvrAddr.sin_family = AF_INET; 
SvrAddr.sin_addr.s_addr = inet_addr(IPAddress); 
SvrAddr.sin_port = htons(PortNumber); 

connect(ClientSocket, (sockaddr*)&SvrAddr, sizeof(SvrAddr)); 



//cout << "Name: "; 
//cin >> login; 

//Send request to login 
int log; 
char * name = new char[128]; 
char * request = new char[128]; 
Users client; 
Users talkto; 


do { 

    cout << "To login press (1) to end press (2). "; 
    cin >> log; 
    flushall(); 

    if (log == 1) { 

     cout << "Username : "; 
     cin.getline(name, 128, '\n'); 
     cout << endl; 
     flushall(); 

     //Set client login info 
     strcpy(client.userName, name); 
     client.message = 1; 



     send(ClientSocket, (char *)&client, sizeof(struct Users), 0); 


     //Recieve acknowledgement 
     recv(ClientSocket, RxBuffer, sizeof(RxBuffer), 0); 
     //create temp users 
     Users temp; 

     memcpy(&temp, RxBuffer, sizeof(struct Users)); 

     //If logged in and received a message of type 2 (acknowledgement) 
     if (temp.message == 2) { 

      cout << "You have logged in." << endl << endl; 

      cout << "Enter user to request user information: "; 
      cin.getline(talkto.userName, 128, '\n'); 
      flushall(); 
      cout << endl; 

      talkto.message = 3; 

      //send request for user information packet 
      send(ClientSocket, (char *)&talkto, sizeof(struct Users), 0); 

      recv(ClientSocket, RxBuffer, sizeof(RxBuffer), 0); 

      memcpy(&temp, RxBuffer, sizeof(struct Users)); 

      //if message received is of type 4 (acknowledgement of user request info) 
      if (temp.message == 4) { 

       cout << "Requested User: " << temp.userName << endl << "Online status: " << temp.online << endl << endl; 
      } 
     } 

     //cout << temp.userName << endl << temp.online << endl << temp.message; 
    } 

} while (log != 2); 


closesocket(ClientSocket); 


WSACleanup(); 



} 

回答

1

你不使用listen()内循环。只有accept()。你也不使用nonblocking socket,但这是你的偏好。另一件事,每次你完成accept你必须使用closesocket。您的recv()也必须在循环中处理,因为不同于发送它可能会在它收到所有数据之前返回。

您的服务器的基本结构:

struct sockaddr_in inAddr; //incoming address. Use it to distinguise between incoming clients 
struct sockaddr_in address; 
unsigned int inLen; 
int recvMsgSize; 
unsigned short port = 20000; 
Socket socket_handle, acceptSocket; 

socket_handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if(socket_handle == INVALID_SOCKET){ 
    //error 
} 

memset(&address, 0, sizeof(address)); 
address.sin_family = AF_INET; 
address.sin_addr.s_addr = htonl(INADDR_ANY); //All incoming addresses 
address.sin_port = htons(port); //port must be unsigned short not int! 
if(bind(socket_handle, (struct sockaddr *)&address, sizeof(address)) < 0){ 
    //error 
} 

if(listen(socket_handle, MAXPENDING) < 0){ 
    //error 
} 

while(true){ 
    acceptSocket = accept(socket_handle, (struct sockaddr *) &inAddr, &inLen)); 
    if(acceptSocket == INVALID_SOCKET){ 
     //error 
    } 

    while(true){ 
     recvMsgSize = recv(acceptSocket, received_data, strlen(received_data), 0); 
     if(recvMsgSize < 0){/*error*/} 
     else if(recvMsgSize == 0){break;} 
     else{/*receive your data*/} 
    } 

    (do other stuff...) 
    closesocket(acceptSocket); 
} 

closesocket(socket_handle); 
WSACleanup(); 

瓦尔特

+0

我需要while循环,因为我一直在寻找其他的连接,他们将派出复式请求登录/视图的信息。 – user2981393

+0

@ user2981393我更正了关于while循环的答案。我的错。 –

+0

我删除了监听,只有接受,然后关闭我的while循环结束时的套接字,但它不再接受新的数据包,就像我的客户端将发送第一个之后的另一个数据包,并且服务器不接受它 – user2981393

相关问题