2013-05-03 39 views
0

服务器和客户端之间的通信正常,但服务器不会将客户端消息转发给其他连接的客户端,而只是发送给客户端。套接字聊天系统 - 将它们广播到所有客户端

我希望服务器通过将它们广播到所有客户端(如聊天系统)来响应传入消息,但保持我的命令系统不与所有客户端分开,但与发件人一起使用。楼下

是来源:

服务器

/*server*/ 
#define WIN32_LEAN_AND_MEAN 
#include <iostream> 
#include <string> 
#include <windows.h> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <process.h> 

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 
#pragma comment (lib, "Ws2_32.lib") 
#pragma comment (lib, "Mswsock.lib") 
#pragma comment (lib, "AdvApi32.lib") 


#define PORT "3490" 

#define SERVER "localhost" 


#include <time.h> 

WSADATA wsa; 

SOCKET s , new_socket; 

struct sockaddr_in server , client; 

int c; 

char *message; 

std::string line; 



DWORD WINAPI ProcessClient (LPVOID lpParameter) 
{ 
    SOCKET AcceptSocket = (SOCKET) lpParameter; 

    // Send and receive data. 
    int bytesSent; 

    int bytesRecv = SOCKET_ERROR; 

    char sendbuf[2000]=""; 
    char sendbuf2[2000]=""; 

    char recvbuf[2000]=""; 

    char timebuf[128]; 

    sprintf(sendbuf, "Hello, it's a test server at %s:%d (commands: 1, 2, exit)\n", SERVER, PORT); 

    bytesSent = send(AcceptSocket, sendbuf, strlen(sendbuf), 0); 

    if (bytesSent == SOCKET_ERROR) 
    { 
     printf("Error at send hello: %ld\n", WSAGetLastError()); 
     goto fin; 
    } 

    while (1) 
    { 
     _strtime(timebuf); 
     ZeroMemory (recvbuf, sizeof(recvbuf)); 

     bytesRecv = recv(AcceptSocket, recvbuf, 32, 0); 

     printf("%s Client said: %s\n", timebuf, recvbuf); 



     sprintf(sendbuf, "%s Client said: %s\n", timebuf, recvbuf); 
     bytesSent = send(AcceptSocket, sendbuf, strlen(sendbuf), 0); 


     if (strcmp(recvbuf, "1") == 0) 
     { 
      sprintf(sendbuf, "You typed ONE\n"); 
      //printf("Sent '%s'\n", sendbuf); 
      bytesSent = send(AcceptSocket, sendbuf, strlen(sendbuf), 0); 

      if (bytesSent == SOCKET_ERROR) 
      { 
       printf("Error at send: %ld\n", WSAGetLastError()); 
       goto fin; 
      } 
     } 
     else if (strcmp(recvbuf, "2") == 0) 
     { 
      sprintf(sendbuf, "You typed TWO\n"); 
      //printf("Sent '%s'\n", sendbuf); 
      bytesSent = send(AcceptSocket, sendbuf, strlen(sendbuf), 0); 

      if (bytesSent == SOCKET_ERROR) 
      { 
       printf("Error at send: %ld\n", WSAGetLastError()); 
       goto fin; 
      } 
     } 
     else if (strcmp(recvbuf, "exit") == 0) 
     { 
      printf("Client has logged out\n", WSAGetLastError()); 
      goto fin; 
     } 
     else 
     { 
      // sprintf(sendbuf, "unknown command\n"); 
      //printf("Sent '%s'\n", sendbuf); 
      // bytesSent = send(AcceptSocket, sendbuf, strlen(sendbuf), 0); 

      if (bytesSent == SOCKET_ERROR) 
      { 
       // printf("Error at send: %ld\n", WSAGetLastError()); 
       goto fin; 
      } 
     } 
    } 

fin: 
    printf("Client processed\n"); 

    closesocket(AcceptSocket); 
    return 0; 
} 




int main(int argc , char *argv[]) 
{ 

    std::cout << ("\nInitialising Winsock..."); 

    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) 
    { 
     std::cout << ("Failed. Error Code : %d",WSAGetLastError()); 
     return 1; 
    } 

    printf("Initialised.\n"); 

    //Create a socket 
    if((s = socket(AF_INET , SOCK_STREAM , 0)) == INVALID_SOCKET) 
    { 
     std::cout << ("Could not create socket : %d" , WSAGetLastError()); 
    } 

    std::cout << ("Socket created.\n"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(3490); 

    //Bind 
    if(bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR) 
    { 
     std::cout << ("Bind failed with error code : %d" , WSAGetLastError()); 
     exit(EXIT_FAILURE); 
    } 

    puts("Bind done"); 



    //Listen to incoming connections 
    listen(s , 3); 



    //Accept and incoming connection 
    std::cout << ("Waiting for incoming connections..."); 

    c = sizeof(struct sockaddr_in); 

    while(true){ 



    while((new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET) { 
     // Create a new thread for the accepted client (also pass the accepted client socket). 
     printf("Client Connected.\n"); 

     DWORD dwThreadId; 
     CreateThread (NULL, 0, ProcessClient, (LPVOID) new_socket, 0, &dwThreadId); 
    } 





     } 

    if (new_socket == INVALID_SOCKET) 
    { 
     std::cout << ("accept failed with error code : %d" , WSAGetLastError()); 
     return 1; 
    } 

    closesocket(s); 
    WSACleanup(); 

    return 0; 
} 

客户

/*client*/ 
#define WIN32_LEAN_AND_MEAN 

#pragma comment(lib,"ws2_32.lib") 

#include <iostream> 
#include <process.h> 
#include <string> 
#include <winsock2.h> 



SOCKET Socket; 

#define SERVER "localhost" 

int PORT = 3490; 

std::string line; 


bool chat = false; 



class Buffer 
{ 

public: 
    int ID; 
    char Message[256]; 
}sbuffer; 



int ClientThread() 
{ 


char buffer[2000]= ""; 

    for(;; Sleep(10)) 
    { 
     if(recv(Socket, buffer, sizeof(sbuffer), NULL)!=SOCKET_ERROR) 
     { 
      strncpy(sbuffer.Message, buffer, sizeof(sbuffer.Message)); 

      std::cout << "<Client:" << sbuffer.ID << ":> " << sbuffer.Message <<std::endl; 

      ZeroMemory (buffer, sizeof(buffer)); 

     } 
    } 

    return 0; 
} 


int main(void) 
{ 
    WSADATA WsaDat; 
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0) 
    { 
     std::cout<<"Winsock error - Winsock initialization failed\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 
     return 0; 
    } 

    // Create our socket 

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    if(Socket==INVALID_SOCKET) 
    { 
     std::cout<<"Winsock error - Socket creation Failed!\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 
     return 0; 
    } 

    // Resolve IP address for hostname 
    struct hostent *host; 
    if((host=gethostbyname(SERVER))==NULL) 
    { 
     std::cout<<"Failed to resolve hostname.\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 
     return 0; 
    } 

    // Setup our socket address structure 
    SOCKADDR_IN SockAddr; 
    SockAddr.sin_port=htons(PORT); 
    SockAddr.sin_family=AF_INET; 
    SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr); 

    // Attempt to connect to server 
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0) 
    { 
     std::cout<<"Failed to establish connection with server\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 
     return 0; 
    } 

    // If iMode!=0, non-blocking mode is enabled. 
    u_long iMode=1; 
    ioctlsocket(Socket,FIONBIO,&iMode); 

    // Main loop 
    for(;;) 
    { 


     // Display message from server 
     char buffer[1000]; 
     memset(buffer,0,999); 
     int inDataLength=recv(Socket,buffer,1000,0); 
     std::cout<<buffer; 



    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ClientThread, NULL, NULL, NULL); 

    for(;; Sleep(10)) 
    { 
     std::string buffer; 
     std::getline(std::cin, buffer); 


     if (send(Socket, buffer.c_str(), buffer.length(), NULL) < 1){ 



     } 
    } 





     int nError=WSAGetLastError(); 

     if(nError!=WSAEWOULDBLOCK&&nError!=0) 
     { 
      std::cout<<"Winsock error code: "<<nError<<"\r\n"; 
      std::cout<<"Server disconnected!\r\n"; 
      // Shutdown our socket 
      shutdown(Socket,SD_SEND); 

      // Close our socket entirely 
      closesocket(Socket); 

      break; 
     } 


     Sleep(1000); 
    } 

    WSACleanup(); 

    system("PAUSE"); 
    return 0; 
} 

请帮我解决这个问题,我是新插入插座的。告诉我该怎么做,因为我会更好地理解代码,并且对将来可能需要它的其他人也是有用的。

回答

1

如果您需要服务器与多个客户端通信,则需要对所有连接的客户端进行某种集合。然后很容易发送到所有连接,或发送到所有连接,但发起连接。

如何做到这一点将不同极大地之间的C和C + +,但为C++看结构和std::vector


在伪代码将是这样的:

while (run_server) 
{ 
    poll_all_connections(); 

    if (have_new_connection()) 
    { 
     accept_new_connection(); 
     add_connection_in_collection(); 
    } 
    else 
    { 
     for (connection in all_connections()) 
     { 
      if (have_input(connection)) 
      { 
       input = read_from_connection(connection); 

       for (send_to in all_connections()) 
        write_to_connection(connection, input) 
      } 
     } 
    } 
} 

如果要实现上面的伪代码,然后从任何连接的输入将被发送到所有连接。

不要忘了从集合中删除的连接,如果连接中断(错误或断开连接。)

+0

C++的方式将是不错!如果你不介意改变源代码的工作方式,你可以随便说一下吗? – 2013-05-03 11:15:46

+0

@SarahLarsen我已经添加了一些伪代码来显示处理它的一种方法。 – 2013-05-03 11:23:36

+0

即时搜索!我很开心,有人会告诉我! ; * - 但我很难理解这个伪示例,可以请你......如果你不介意把它植入我已发布的服务器中,那么我可以看到并学习它是如何正确完成的? – 2013-05-03 11:24:59

1

你必须维护所有客户端套接字连接的列表,然后将数据发送到每一个客户端一个一个。

,或者你可以使用线程来实现这个如下: -

Server-thread() 
{ 
    while(true) 
    { 
     /// Accept Connection in ClientSocket. 

     HandleClient-Thread(ClientSocket) ; // launch a thread for each client . 
    } 

    } 

    HandleClient-Thread(ClientSocket) 
    { 
    // handle this client here 

    } 
+0

你可以请一步一步向我展示或植入服务器内?这将是非常有益的,更好地理解:) – 2013-05-03 11:30:43

+0

@你说要做你的家务。只需维护所有传入连接的数组,然后从一个循环中将数据逐个发送给所有这些@ Joachim Pileborg已经向您显示了这些数据。 – birubisht 2013-05-03 11:34:01

+0

我只是问有礼貌,如果你不介意告诉我如何让我能理解它,它会帮助任何人在脚下......这里没有家庭作业......我只是不知道如何做到这一点 – 2013-05-03 11:35:34