客户端 - 服务器回声聊天(多路复用I / O +线程)

时间:2017-05-10 21:35:19

标签: c multithreading sockets server multiplexing

我刚刚开始学习C语言,而且我正试图处理Windows套接字。

问题是服务器只能接受和发送一次消息。 我使用了调试模式,看到工作从服务器部分停止在select()中。它在客户端似乎很好(但我不确定)并且在我的代码中看不到问题。但我有这样的结果。怎么了?

我注意到我的tv.tv_sec没有定义,我在选择之前就做了,没有任何改变。

只是为了确定:因为我需要接收和发送消息,所以我不需要在accept()中写入描述符,对吗?

客户端使用CreateThread函数,我尝试发送消息。发送在main()

中的while(1)循环中

服务器部分:

self.popupConstraintX.constant = x
self.popupConstraintY.constant = y

NSAnimationContext.runAnimationGroup({context in
  context.duration = 0.25
  context.allowsImplicitAnimation = true

  self.graphPopup.alphaValue = 1.0
  self.view.layoutSubtreeIfNeeded()

}, completionHandler:nil)

客户端部分(它使用位于代码末尾的CreateThread函数):

int main(int argc, char* argv[])
{
    /* definitions, WSAStartup(), socket(), bind(), listen() 
    Listening socket is a returned value of listen() function*/

        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);

        while (1)
        {
            // SELECT (LISTENING SOCKET)
            FD_ZERO(&readSet);
            FD_SET(listeningSocket, &readSet);
            tv.tv_sec = 5;
            printf("Listening: Read FD: %d; Write FD : %d;\n", FD_ISSET(listeningSocket, &readSet), FD_ISSET(listeningSocket, &writeSet));
            if ((retVal = select(listeningSocket + 1, &readSet, NULL, NULL, 0)) == SOCKET_ERROR)
            {
                printf("Select error ");
                break;
            }
            else if (retVal == 0)
            {
                printf(". . .\n");
                continue;
            }
            else
            {
                // READ SD
                if ((FD_ISSET(listeningSocket, &readSet)) != SOCKET_ERROR)
                {
                    if ((newSocketDescriptor = accept(listeningSocket, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR)
                    {
                        printf("Accept error ");
                        break;
                    }
                    FD_ZERO(&readSet);
                    FD_SET(newSocketDescriptor, &readSet);

                    HOSTENT *hst = gethostbyaddr((const char *)&serverAddr.sin_addr.s_addr, 4, AF_INET);
                    printf("Welcome %s (%s:%d) new connected\n", hst->h_name, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
                    printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));

                    // READ
                    if (FD_ISSET(newSocketDescriptor, &readSet) != 0)
                    {
                        if ((numBytes = recv(newSocketDescriptor, &bufferData[0], sizeof(bufferData), 0)) == SOCKET_ERROR)
                        {
                            printf("Recv failed \n");
                            freeSocketInformation(newSocketDescriptor);
                            break;
                        }

                        bufferData[numBytes] = '\0';
                        printf("Client -> Server: %s\n", &bufferData[0]);
                    }

                    // WRITE
                    FD_ZERO(&writeSet);
                    FD_SET(newSocketDescriptor, &writeSet);

                    printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));
                    if (FD_ISSET(newSocketDescriptor, &writeSet) != 0)
                    {
                        //fgets(&bufferData[0], sizeof(bufferData), stdin);
                        if (send(newSocketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0) == SOCKET_ERROR)
                        {
                            printf("Send error ");
                            freeSocketInformation(newSocketDescriptor);
                            break;
                        }
                        bufferData[numBytes] = '\0';
                        printf("Server -> Client: %s\n", &bufferData[0]);

                    }
                    printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));

                    FD_SET(newSocketDescriptor, &readSet);
                }
            }
        }
        //FD_CLR(listeningSocket, &readSet);
        closesocket(newSocketDescriptor);
    } while (FALSE);
    printf("- Error code: %d\n", WSAGetLastError());
    closesocket(listeningSocket);
    WSACleanup();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

嗯,我自己解决了。条件

if ((FD_ISSET(listeningSocket, &readSet)) != 0) 

一直工作(1)循环,它应该在accept()函数之后完成。 另外,我在readSet的FD_SET之后的while(1)的开头添加了这些行:

if (newSocketDescriptor)
{
    FD_SET(newSocketDescriptor, &readSet);
}

聊天开始有效,但有很多工作要做:)