【问题标题】:Winsock single client server send and receive simultaneouslyWinsock 单客户端服务器同时发送和接收
【发布时间】:2014-12-22 20:57:53
【问题描述】:

我在使用 C++ 中的简单 Winsock 聊天应用程序时遇到问题。我编写了一个代码,使用户能够选择是要发送数据还是接收数据,并根据用户的选择执行适当的功能。我想要实现的是用户可以发送和接收数据。我怎么能接近它?请注意,我不想使用多个客户端,我只想通过服务器发送和接收数据,同时通过客户端发送和接收数据。

编辑:我添加了我的代码。

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <ctime>


int main()
{
    string IP;
    int userType;

    // Ask the user if he is server or client
    cout << "Hi, which type of user are you? 1 - Server, 2 - Client" <<endl;
    cin >> userType;

    // depending on the declared user type, execute the appropriate code
    if (userType == 1)
    {
        //initialize winsock and create a socket
        WSAData wsaData; // initialize
        iResult = WSAStartup(MAKEWORD(2,1), &wsaData);

        if (iResult != NO_ERROR) // check for errors
             cout << "Error at WSAStartup()" <<endl;
        else
             cout << "WSAStartup() is OK." <<endl;

        // create socket
        sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
        if (sockSocket == INVALID_SOCKET) // check for errors
        {
            cout << "Error at socket(): " << WSAGetLastError();
            WSACleanup();
            return true;
        }
        else
            cout << "Socket() is OK." <<endl;
        return true;

        // bind to socket
        service.sin_addr.s_addr = inet_addr("0.0.0.0");
        service.sin_family = AF_INET;
        service.sin_port = htons(55555);

        if (bind(sockSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) // cheking for errors
        {
            cout << "Bind() failed." << endl;
            closesocket(sockSocket);
            return true;
        }
        else
            cout << "Bind() is OK." <<endl;


        // listen
        listen(sockSocket, SOMAXCONN);
        if (listen(sockSocket, 10) == SOCKET_ERROR) // check for errors
        {
            cout << "Error listening on socket." << endl;
            return true;
        }
        else
            cout << "Listen() is OK." <<endl;

        //accept connection
        servlen = sizeof(service);
        cout << "Waiting for user to connect..." << endl;

        acceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(acceptSocket = accept(sockSocket, (SOCKADDR*)&service, &servlen))
        {
            cout << "A coonnection was found" <<endl<<endl;
        }
        sockSocket = acceptSocket;

        // receive messages
        do
        {
            std::string message;
            char Buffer[512];
            iResult = recv(sockSocket, Buffer, 512, 0);
            Buffer[iResult] = '\0';
            message = Buffer;
            currentDate();
            std::cout << Buffer <<endl<<endl;

        }while(iResult>0);

        closesocket(sockSocket);
        WSACleanup();
    }

    else if (userType == 2)
    {
        // exactly the same code as for server part to initialize and create socket

        // ask  for the ip the user wants to connect to
        cout << "Hi what's the IP that you want to connect to?" <<endl;
        cin >> IP;

        // connect to socket
        conService.sin_addr.s_addr = inet_addr(IP); // connect to the ipnuted IP
        conService.sin_family = AF_INET;
        conService.sin_port = htons(55555); // should the port also be the argument?

        if (connect(sockSocket, (SOCKADDR*)&conService, sizeof(conService)) == SOCKET_ERROR) // check for errors
        {
            cout << "Failed to connect: " << WSAGetLastError();
            WSACleanup();
            return true;
        }
        else
        {
            cout << "Connected." <<endl;
        }

        // send messages
        for (;;)
        {
            std::string message;
            std::getline(std::cin, message);
            unsigned int Length = strlen(message.c_str());
            if(Length>512)
                Length = 512;
            currentDate();
            iResult = send(sockSocket, message.c_str(),Length,0);
        }
        closesocket(sockSocket);
        WSACleanup();
    }

    WSACleanup();
    return 0;
}

Edit2:正如 Lemy 在评论中建议的那样,我需要有第二个线程(因为第一个线程只是主函数中发生的事情)。据我了解,我可以使用 CreateThread 函数。我如何发送和接收消息的问题已解决(我应该创建另一个线程),但现在我在实施该解决方案时遇到了问题。正如我在 Lemy 的回答下面的评论中所写,我在使用 CreateThread 函数 (HANDLE hThread = CreateThread(0,0,&ReadingThread,acceptSocket,0,&dwThreadID);) 的行中遇到这样的错误:

  1. 从“SOCKET {aka unsigned int}”到“PVOID {aka void*}”的无效转换 [-fpermissive]|和
  2. 从 'DWORD {aka long unsigned int}' 到 'PDWORD {aka long unsigned int*}' 的无效转换 [-fpermissive]

对此有什么提示吗?希望这能让我的问题更具体(如果不是,请告诉我应该详细说明什么)。

【问题讨论】:

  • @Qix,我添加了代码
  • 稍微重构一下代码,特别是 WSAStartup/WSACleanup 调用不平衡。也就是说,我不相信你真的写了这个程序,否则你可以问更具体的问题如何实现。
  • Ulirich,这段代码看起来像这样,因为 1. 我对 C++ 和 Winsock 完全陌生,2. 我把它组织成单独文件中的类和方法,但我想把它放到“一个代码”,以便更容易在此处显示。不过,我不知道如何才能更具体地回答我的问题

标签: c++ winsock


【解决方案1】:

您需要让客户端和服务器在连接的整个生命周期内持续在后台读取数据,然后它们可以在需要时并行发送数据。将您的阅读逻辑移到单独的线程中,例如:

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <ctime>

DWORD WINAPI ReadingThread(LPVOID param)
{
    SOCKET s = (SOCKET) param;
    char Buffer[512];
    int iResult;

    do
    {
        iResult = recv(s, Buffer, 512, 0);
        if (iResult <= 0) break;
        Buffer[iResult] = '\0';
        std::cout << "Recv: " << message << std::endl;
    }
    while (true);

    return 0;
}

int main()
{
    int userType;
    HANDLE hThread;
    DWORD dwThreadID;

    //initialize winsock and create a socket
    WSAData wsaData; // initialize
    iResult = WSAStartup(MAKEWORD(2,1), &wsaData);

    if (iResult != NO_ERROR) // check for errors
    {
        std::cout << "Error at WSAStartup()" << std::endl;
        return 0;
    }

    std::cout << "WSAStartup() is OK." << std::endl;

    // Ask the user if he is server or client
    std::cout << "Hi, which type of user are you? 1 - Server, 2 - Client" << std::endl;
    std::cin >> userType;

    // depending on the declared user type, execute the appropriate code
    if (userType == 1)
    {
        // create socket
        sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
        if (sockSocket == INVALID_SOCKET) // check for errors
        {
            std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
            WSACleanup();
            return 0;
        }

        std::cout << "Socket() is OK." << std::endl;

        // bind to socket
        service.sin_addr.s_addr = INADDR_ANY;
        service.sin_family = AF_INET;
        service.sin_port = htons(55555);

        if (bind(sockSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) // cheking for errors
        {
            std::cout << "Error at bind(): " << WSAGetLastError() << std::endl;
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        std::cout << "Bind() is OK." << std::endl;

        // listen
        if (listen(sockSocket, 10) == SOCKET_ERROR) // check for errors
        {
            std::cout << "Error at listen(): " << WSAGetLastError() << std::endl;
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        std::cout << "Listen() is OK." << std::endl;

        //accept connection
        servlen = sizeof(service);
        std::cout << "Waiting for user to connect..." << std::endl;

        acceptSocket = accept(sockSocket, (SOCKADDR*)&service, &servlen);
        if (acceptSocket != INVALID_SOCKET)
        {
            std::cout << "Error at accept(): " << WSAGetLastError() << std::endl;
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        std::cout << "A client has connected" << std::endl << std::endl;

        // receive messages
        hThread = CreateThread(NULL, 0, &ReadingThread, (void*)acceptSocket, 0, &dwThreadID);
        if (!hThread)
        {
            std::cout << "Error at CreateThread(): " << GetLastError() << std::endl;
            closesocket(acceptSocket);
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        // send messages
        do
        {
            std::string message;
            if (!std::getline(std::cin, message))
                break;

            if (send(acceptSocket, msg.c_str(), msg.length(), 0) == SOCKET_ERROR)
            {
                std::cout << "Error at send(): " << WSAGetLastError() << std::endl;
                break;
            }
        }
        while (true);

        closesocket(acceptSocket);

        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);

        closesocket(sockSocket);
        WSACleanup();
    }

    else if (userType == 2)
    {
        // create socket
        sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
        if (sockSocket == INVALID_SOCKET) // check for errors
        {
            std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
            WSACleanup();
            return 0;
        }

        std::cout << "Socket() is OK." << std::endl;

        // ask  for the ip the user wants to connect to
        std::string IP;
        std::cout << "Hi what's the IP that you want to connect to?" << std::endl;
        std::cin >> IP;

        // connect to socket
        conService.sin_addr.s_addr = inet_addr(IP.c_str()); // connect to the ipnuted IP
        conService.sin_family = AF_INET;
        conService.sin_port = htons(55555); // should the port also be the argument?

        if (connect(sockSocket, (SOCKADDR*)&conService, sizeof(conService)) == SOCKET_ERROR) // check for errors
        {
            std::cout << "Failed to connect: " << WSAGetLastError() << std::endl;
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        std::cout << "Connected." << std::endl;

        // receive messages
        hThread = CreateThread(NULL, 0, &ReadingThread, (void*)sockSocket, 0, &dwThreadID);
        if (!hThread)
        {
            std::cout << "Error at CreateThread(): " << GetLastError() << std::endl;
            closesocket(sockSocket);
            WSACleanup();
            return 0;
        }

        // send messages
        do
        {
            std::string message;
            if (!std::getline(std::cin, message))
                break;

            if (send(sockSocket, msg.c_str(), msg.length(), 0) == SOCKET_ERROR)
            {
                std::cout << "Error at send(): " << WSAGetLastError() << std::endl;
                break;
            }
        }
        while (true);

        closesocket(sockSocket);

        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);

        WSACleanup();
    }

    else
    {
        std::cout << "Invalid type entered!" << std::endl;
        WSACleanup();
        return 0;
    }

    return 0;
}

【讨论】:

  • 雷米,非常感谢您的帮助。我正在尝试实施您的解决方案,尽管我遇到了这样的错误(对于这行代码:HANDLE hThread = CreateThread(0,0,&ReadingThread,acceptSocket,0,&dwThreadID);) 1)来自 'SOCKET {aka unsigned int}' 到 'PVOID {aka void*}' [-fpermissive]|和 2) 从 'DWORD {aka long unsigned int}' 到 'PDWORD {aka long unsigned int*}' [-fpermissive] 的无效转换
  • 我修复了 SOCKET 转换错误,但是 PDWORD 错误来自哪里?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
  • 2021-12-04
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
相关资源
最近更新 更多