c++ winsock - server communicates only with single client while it should communicate with every client

StackOverflow https://stackoverflow.com/questions/23278941

  •  09-07-2023
  •  | 
  •  

Question

I am writing a single chat program with GUI. I wanted to write a server that would accept many clients. Every client can connect successfuly. But there is a strange problem with sending and receiving data. I use select() and a thread to handle many sockets at the same time. If a client sends some data to server, it will receive it and send it back to that client (the client is especially written without "prediction"). But the server won't send it further to another clients (like every client had its own private conversation with the server). Here's my code:

// this is rewritten from the Beej's tutorial with a little and insignificant changes
/* in the thread */
fd_set mainfd;
fd_set readfd;
// sin-size, newfd, maxfd - int
while(TRUE)
{
    readfd = mainfd;
    if(select(maxfd+1, &readfd, NULL, NULL, NULL) == -1)
    {
        MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
        itoa(GetLastError(), buf, 10);
        MessageBoxA(NULL, buf, buf, 0);
        break;
    }
    for(int i = 0; i <= maxfd; i++)
    {
        char* psr;
        char srMsg[256];
        if(FD_ISSET(i, &readfd))
        {
            if(i == mainSocket)
            {
                sin_size = sizeof(their_addr);
                newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
                if(newfd == SOCKET_ERROR)
                {
                    AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
                }
                else
                {
                    FD_SET(newfd, &mainfd);
                    if(newfd > maxfd)
                    {
                        maxfd = newfd;
                    }

                }
            }
            else
            {
                len = recv(i, srMsg, 256, 0);
                if(len == 0 || len == SOCKET_ERROR)
                {
                    AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
                    close(i);
                    FD_CLR(i, &mainfd);
                }
                else
                {
                        AddTextToEdit(hStaticChat, srMsg, TRUE);
                        for(int j = 0; j <= maxfd; j++)
                        {
                          if(FD_ISSET(j, &readfd))
                          {
                                  send(j, srMsg, len, 0);
                          }
                        }

                }
             }
        }
     }
}
Was it helpful?

Solution

You are only sending data to the clients whos fd is in readfd, that is, only to that one which just communicated to you. Try to test FD_ISSET(j, mainfd) instead.

OTHER TIPS

This code is not valid under WinSock. Windows does not deal with sockets using integer file descriptors like other platforms do. Sockets are represented using actual kernel objects instead, so you can't use loop counters as socket handles and such. There is also API differences (closesocket() instead of close(), maxfd is ignored by select(), FD_XXX() expect SOCKET handles instead of int, etc).

On Windows, you need to use something more like this instead:

fd_set mainfd;
SOCKET newfd;
int sin_size;
...

while(TRUE)
{
    fd_set readfd = mainfd;
    if (select(0, &readfd, NULL, NULL, NULL) == SOCKET_ERROR)
    {
        itoa(WSAGetLastError(), buf, 10);
        MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
        MessageBoxA(NULL, buf, buf, 0);
        break;
    }

    for(int i = 0; i < readfd.fd_count; i++)
    {
        if (readfd.fd_array[i] == mainSocket)
        {
            sin_size = sizeof(their_addr);
            newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
            if (newfd == INVALID_SOCKET)
            {
                AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
            }
            else
            {
                // Note that fd_set can only hold FD_SETSIZE (64) sockets as a time!
                FD_SET(newfd, &mainfd);
            }
        }
        else
        {
            char srMsg[257];

            len = recv(readfd.fd_array[i], srMsg, 256, 0);
            if (len < 1)
            {
                if (len == 0)
                    AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
                else
                    AddTextToEdit(hStaticChat, "* Error: couldn't read from a client connection.", TRUE);

                closesocket(readfd.fd_array[i]);
                FD_CLR(readfd.fd_array[i], &mainfd);
            }
            else
            {
                srMsg[len] = 0;
                AddTextToEdit(hStaticChat, srMsg, TRUE);

                for (int j = 0; j < mainfd.fd_count; j++)
                {
                    if (mainfd.fd_array[i] != mainSocket)
                        send(mainfd.fd_array[j], srMsg, len, 0);
                }
            }
        }
     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top