套接字聊天系统 - 将它们广播给所有客户

时间:2013-05-03 11:04:45

标签: c++ chat winsock

服务器和客户端之间的通信正常,但服务器不会将客户端消息转发给其他连接的客户端,而只转发给发件人。

我希望服务器通过将它们广播到所有客户端(如聊天系统)来对传入消息做出反应,但保留我的命令系统,而不是使用所有客户端,而是使用发件人。

以下是来源:

服务器

    /*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;
}

请帮我解决,我是socket的新手。告诉我该怎么做,因为我会更好地理解代码,它对将来可能需要它的其他人也很有用。

2 个答案:

答案 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)
            }
        }
    }
}

如果您实现上述伪代码,则任何连接的输入都将发送到所有连接。

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

答案 1 :(得分: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 

   }