socket recv读取没有消息

时间:2018-01-25 06:08:24

标签: c++ sockets

以下代码是应该在两个应用程序之间进行通信的应用程序。在一个exe(A)中,用户键入一条消息,并在另一个exe(B)中打印消息。

该计划的流程:

  1. 两个exe都调用connectTo,以便他们准备好发送和接收消息。
  2. 用户在控制台窗口中键入要发送的消息,该窗口在A exe中调用sendMsg。当在B中收到消息时,消息将在B控制台窗口中打印。
  3. 问题是收到的消息有时是空的。当我在A中输入1234十次时,在B中打印十条消息,其中只有5-6个是1234,其余的是空的。从B到A的情况相同。

    ++++++++++++++++++++++++++ 整个计划 ++++++++++++++++++++++++++

    Header.h

    #pragma once
    
    #include <WinSock2.h>
    #include <Windows.h>
    #include <mutex>
    #include <thread>
    
    class CommuWin
    {
    private:
        std::mutex m_accessMutexSend;
        std::mutex m_accessMutexReceive;
        std::thread m_sendThread;
        std::thread m_receiveThread;
        bool m_IsSendReady = false;
        bool m_IsRecvReady = false;
        SOCKET m_outSocket;
        SOCKADDR_IN m_outAddr;
        SOCKET m_inSocket;
        SOCKADDR_IN m_inAddr;
    
    public:
        CommuWin(int InPort, int OutPort);
        ~CommuWin();
        int connectTo();
        int sendMsg(const char* message);
        int StartReceiveMsg();
        bool GetRecvStatus();
        bool GetSendStatus();
    private:
        void SetRecvStatus(bool ready);
        void SetSendStatus(bool ready);
        int SetupRecvEnd();
        int SetupSendEnd();
        int sendMsgTo(const char* message);
        int ReceiveMsgFrom();
    
    };
    

    Source.cpp

    #pragma comment(lib, "Ws2_32.lib")
    #include "Header.h"
    #define OKAY (1)
    #define ERROR (-1)
    #define MAX_MSG_SIZE (200)
    class NetworkServices
    {
    public:
        static int sendMessage(SOCKET curSocket, const char* message, int messageSize);
        static int receiveMessage(SOCKET curSocket, char * buffer, int bufSize);
    };
    int NetworkServices::sendMessage(SOCKET curSocket, const char* message, int messageSize)
    {
        return send(curSocket, message, messageSize, 0);
    }
    int NetworkServices::receiveMessage(SOCKET curSocket, char * buffer, int bufSize)
    {
        return recv(curSocket, buffer, bufSize, 0);
    }
    CommuWin::CommuWin(int InPort, int OutPort)
    {
        WSAData wsaData;
        WORD DLLVersion;
        DLLVersion = MAKEWORD(2, 1);
        int r = WSAStartup(DLLVersion, &wsaData);
        ///////////////////////////////////////////////////////////////////////
        m_outSocket = socket(AF_INET, SOCK_STREAM, NULL);
        m_outAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        m_outAddr.sin_family = AF_INET;
        m_outAddr.sin_port = htons(OutPort);
        m_inSocket = socket(AF_INET, SOCK_STREAM, NULL);
        m_inAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        m_inAddr.sin_family = AF_INET;
        m_inAddr.sin_port = htons(InPort);
    }
    CommuWin::~CommuWin()
    {   
    }
    int CommuWin::connectTo()
    {
        printf("connect to");
        printf("\n");
        m_sendThread = std::thread(
            &CommuWin::SetupSendEnd,
            this);
        m_receiveThread = std::thread(
            &CommuWin::SetupRecvEnd,
            this);
        return OKAY;
    }
    int CommuWin::SetupSendEnd()
    {
        SOCKET sListen; 
        sListen = socket(AF_INET, SOCK_STREAM, NULL);
        bind(sListen, (SOCKADDR*)&m_outAddr, sizeof(m_outAddr));
        listen(sListen, SOMAXCONN);
        m_outSocket = accept(sListen, NULL, NULL);
        if (m_outSocket != INVALID_SOCKET)
        {
            SetSendStatus(true);
            printf("accepted\n");
        }
        return OKAY;
    }
    int CommuWin::SetupRecvEnd()
    {
        int connectSucceed = 0;
        do
        {
            Sleep(1000);
            connectSucceed = connect(m_inSocket, (SOCKADDR*)&m_inAddr, sizeof(m_inAddr));
    
        } while (connectSucceed == SOCKET_ERROR);
        SetRecvStatus(true);
        printf("connected\n");
        return OKAY;
    }
    int CommuWin::sendMsg(const char* message)
    {
        if (GetSendStatus())
        {
            m_sendThread.detach();
            m_sendThread = std::thread(
                &CommuWin::sendMsgTo,
                this,
                message);
        }
        return OKAY;
    }
    int CommuWin::sendMsgTo(const char* message)
    {
        NetworkServices::sendMessage(m_outSocket, message, (int)strlen(message));
        return OKAY;
    }
    int CommuWin::StartReceiveMsg()
    {
        if (GetRecvStatus())
        {
            m_receiveThread.detach();
            m_receiveThread = std::thread(
                &CommuWin::ReceiveMsgFrom,
                this);
        }
        return OKAY;
    }
    int CommuWin::ReceiveMsgFrom()
    {
        while (true)
        {
            char message[MAX_MSG_SIZE];
            ZeroMemory(message, MAX_MSG_SIZE);
            NetworkServices::receiveMessage(m_inSocket, message, sizeof(message));
            printf(message);
            printf("\n");
        }
        return OKAY;
    }
    void CommuWin::SetRecvStatus(bool ready)
    {
        std::lock_guard<std::mutex> lock(m_accessMutexReceive);
        m_IsRecvReady = ready;
    
    }
    void CommuWin::SetSendStatus(bool ready)
    {
        std::lock_guard<std::mutex> lock(m_accessMutexSend);
        m_IsSendReady = ready;
    }
    
    bool CommuWin::GetRecvStatus()
    {
        std::lock_guard<std::mutex> lock(m_accessMutexReceive);
        return m_IsRecvReady;
    }
    bool CommuWin::GetSendStatus()
    {
        std::lock_guard<std::mutex> lock(m_accessMutexSend);
        return m_IsSendReady;
    }
    

    的main.cpp

    #include "stdafx.h"
    #include "Header.h"
    #include <iostream>
    #include <string>
    int main(int argc, char *argv[])
    {
        std::cout << argc <<std::endl;
        int Inport = std::stoi(argv[1]);
        int Outport = std::stoi(argv[2]);
        //std::cout << "inport = " << argv[1] << " outport = " << argv[2] << std::endl;
        std::cout << "inport = " << Inport << " outport = " << Outport << std::endl;
        CommuWin com(Inport, Outport);
        com.connectTo();
        while (true)
        {
            if (com.GetSendStatus() && com.GetRecvStatus())
            {
                com.StartReceiveMsg();
                break;
            }
        }
        while (true)
        {
            std::cout << "Enter Send Message" << std::endl;
            std::string msg;
            std::cin >> msg;
            com.sendMsg(msg.c_str());
        }
        return 0;
    }
    

2 个答案:

答案 0 :(得分:1)

如果要发送和接收消息,则必须编写一些代码才能执行此操作。没有任何代码可以发送或接收消息。如果您认为存在,请专门指出用于确定您收到的数据是否是一条或多条消息的代码。你不能这样做。

TCP 是一种消息协议。如果您需要在TCP之上的消息协议,则必须实现一个。看看执行此操作的协议,例如HTTP,IRC或FTP,看看它是如何完成的。

如果记录收到的字节数,您将看到收到的所有数据都已收到。如果您需要,将数据拆分成信息是您的工作 - 它本身不会发生。

答案 1 :(得分:1)

您的代码存在多个问题。首先,您需要检查所有功能的结果,包括但不限于sListenbindlistenrecv

 NetworkServices::receiveMessage(m_inSocket, message, sizeof(message));
 // Without checking recv result there is no way to guess how much
 // bytes are actually stored in `message`, if any. Also boldly assuming
 // that `message` is null terminated and represents a proper format string
 // is dangerous.
 printf(message);

您还需要仔细初始化所有内容,尤其是sockaddr结构,在这种情况下可能会部分初始化。您正在使用多个线程但执行的同步不足。由(可能是分离的)后台线程执行的方法sendMsgTo(const char* message)接收指向可能随时失效的字符串缓冲区的指针。