简体   繁体   中英

Winsock single client server send and receive simultaneously

I have a problem with simple Winsock chat application in C++. I've written a code that enables the user to choose if he wants to send data or receive the data and depending on users choice, the appropriate functions are executed. What I would like to achieve, is that the user can BOTH send and receive data. How could I approach it? Please note that I don't want to use multiple client, I just want to send and receive data by server and send and receive data by client simultaneously.

Edit: I added my code.

#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: As Lemy suggested in the comment, I need to have a second thread (as the first one is simply what's going on in the main function). From what I understood, I can use CreateThread function. My problem of how to both send and receive messages is solved (I should create another thread), but now I have problem with implementing the solution. As I wrote in the comment below Lemy's answer, I get such error referring to the line where I use CreateThread function (HANDLE hThread = CreateThread(0,0,&ReadingThread,acceptSocket,0,&dwThreadID);):

  1. invalid conversion from 'SOCKET {aka unsigned int}' to 'PVOID {aka void*}' [-fpermissive]| and
  2. invalid conversion from 'DWORD {aka long unsigned int}' to 'PDWORD {aka long unsigned int*}' [-fpermissive]

Any hints for that? Hope this makes my question more specific(if not pls tell me what should I specify more).

You need to have the client and server continuously reading in the background for the lifetime of the connection, and then they can send data in parallel whenever needed. Move your reading logic into a separate thread, eg:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM