不能NULL-终止recv缓冲区

时间:2016-10-20 11:54:53

标签: c++ tcp null network-programming recv

尝试从此处解决问题:https://stackoverflow.com/questions/40136218/c-non-sense-data-between-recv-calls/

在尝试展示我尝试的内容之前,我已经尝试了很多方法从buf取消终止recv,这里是我挂钩recv的代码功能和我记录数据:

typedef int (WINAPI *SendPtr)(SOCKET s, const char* buf, int len, int flags);
HMODULE hLib = LoadLibrary("wsock32.dll");
SendPtr pSend = (SendPtr)GetProcAddress(hLib, "send");
int WINAPI MySend(SOCKET s, const char* buf, int len, int flags);
SendPtr pRecv = (SendPtr)GetProcAddress(hLib, "recv");
int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags);
extern HMODULE hDLL;
__declspec(dllexport) LRESULT WINAPI MyProcedure(int code, WPARAM wp, LPARAM lp);
HMODULE g_hModule = NULL ;

INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
    switch(Reason)
    {
        case DLL_PROCESS_ATTACH:

            CreateConsole();
            g_hModule = hDLL;
            DisableThreadLibraryCalls(hDLL);
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)pSend, MySend);
            if(DetourTransactionCommit() == NO_ERROR)


            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)pRecv, MyRecv);
            if(DetourTransactionCommit() == NO_ERROR)


            return TRUE;

    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}


// ---------- SEND ------------


int WINAPI MySend(SOCKET s, const char* buf, int len, int flags)
{
    int i = 0;
    int ret = pSend(s, buf, len, flags);
    while (i < ret && buf)
    {
        int len = strlen(buf) +1;
        buf += len;
        i += len;
    }


    return ret;
}

// ---------- RECV ------------

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
{

    int i = 0;
    int ret = pRecv(s, buf, len, flags);

    while (i < ret && buf)
    {           
        cout<<buf<<endl;

        int len = strlen(buf) +1;
        buf += len;
        i += len;    
    }

    return ret;
}

我测试了什么

我已经尝试检查buf的字节数,然后添加终结符:

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
    {

        int i = 0;
        int ret = pRecv(s, buf, len, flags);
        buf[ret] = '\0';

        while (i < ret && buf)
        {           
            cout<<buf<<endl;

            int len = strlen(buf) +1;
            buf += len;
            i += len;    
        }

        return ret;
    }

结果呢?数据被破坏为垃圾数据,如@ÿÿÿ^¡5~ç和我试图提取数据的程序,崩溃。

我已尝试将数据存储到矢量中。

std::vector<char> buffer(1025);

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
{

    int i = 0;
    int ret = pRecv(s, buffer.data(), buffer.size() - 1, 0);



    while (i < ret && buffer.data())
    {

        cout<<buffer.data()<<endl;

        int len = strlen(buffer.data()) +1;
        buf += len;
        i += len;

    }


    return ret;
}

有点工作,存储一些数据然后程序崩溃,改变矢量的大小也不起作用。

1 个答案:

答案 0 :(得分:1)

使用TCP ...

您不能将来自网络的任意数据视为字符串。您需要建立一个协议来确定数据的格式化方式,以及何时收到一些您可以理解的数据。

然后,您需要从网络接收数据,直到您在尝试解释之前获得了大量可以理解的数据。

用于通过TCP发送字符串的简单协议将是

[X = 32 bit network byte order unsigned int string length]
Next X bytes are the string

然后,在获得X + 4字节后,您可以解释数据,从4字节的偏移量开始作为字符串,并且要么知道在发送时包含了nul终止符,要么放入nul终止符在缓冲区末尾的客户端。超过X + 4字节的任何数据都将是下一个字符串的开头,否则如果完成发送数据,客户端将断开连接。

此时你可以打印出来。

如果您需要非常原始的调试数据,您只需打印出您收到的每个字节的十六进制值,如:

Recv returned 4 bytes:  0xa7 0x42 0x8b 0x44

每次收到回报,但这通常没那么有用。