Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
recv()直到收到NUL字节为止?_C_Sockets_Winsockets - Fatal编程技术网

recv()直到收到NUL字节为止?

recv()直到收到NUL字节为止?,c,sockets,winsockets,C,Sockets,Winsockets,我试图一次从服务器接收一个数据包,因为数据包速度太快,而且每个数据包的大小都未定义,调用recv()读取字节数将读取第一个数据包,也可能是第二个数据包的一部分。由于每个数据包都以NULL结尾,所以我认为应该逐字节读取,直到收到一个NULL字节 int recvLen = 0; char TB; char recvBuffer[1024]; while (recv(Socket, &TB, 1, 0) > 0 && TB != 0 &a

我试图一次从服务器接收一个数据包,因为数据包速度太快,而且每个数据包的大小都未定义,调用recv()读取字节数将读取第一个数据包,也可能是第二个数据包的一部分。由于每个数据包都以NULL结尾,所以我认为应该逐字节读取,直到收到一个NULL字节

    int recvLen = 0;
    char TB;
    char recvBuffer[1024];
    while (recv(Socket, &TB, 1, 0) > 0 && TB != 0 && recvLen < 1024)
    {
        recvBuffer[recvLen] = TB;
        recvLen++;
    }

我一直不明白为什么通信协议不支持程序员期望能够做到的一个用例:交换任意大小的blob,发送和接收在边界上对齐


所以这里没有真正的捷径。您需要保留一个持久性缓冲区,用于保存上一次调用recv时留下的任何数据。在接收数据时,不断向末尾添加数据,每次找到数据时返回到终止零。您可能至少有一部分后续数据包,因此将其移动到缓冲区的开头,作为下次调用时的初始状态。

有几种方法可以做到这一点

选项#1:在发送任何信息之前,在数据包前面发送一个int,其中包含数据包的大小。读取此整数,然后分配一个缓冲区,该缓冲区是您刚刚收到的整数的长度。然后您可以一次接收整个数据包


选项2:一次读取1024字节。recv()将返回读取的字节数。然后,可以使用strlen()确定缓冲区中是否有多个数据包。最有意义的做法可能是递归(假设您可以在1024字节中包含多个数据包);因此,您可以根据空字节分割数据包

创建一个缓冲区并从中提取协议消息。如果缓冲区不包含完整的消息,则执行recv(),直到它包含完整的消息为止。下面是一个缓冲套接字的简单C实现(经过简单测试,在MS VS2008上编译):

关键是TCP/IP没有消息边界的概念,因此recv()可以将请求的字节数返回1。接收到的缓冲区可能包含多条甚至部分消息

这段代码只是将接收到的数据附加到缓冲区中。协议从缓冲区请求字节,缓冲区从套接字填充。当字节被删除时,剩余的缓冲数据被移到缓冲区的开头

在这种情况下,请求两个字节,转换为一个长度,然后请求剩余的字节。如果无法满足请求,将接收更多数据


希望这有帮助。

您可以更改数据包格式吗?也就是说,通过包含一个指定数据包长度的报头?您不想在这里使用strlen-如果根本没有任何NUL怎么办?这个问题特别基于检测空字节。斯特伦就是这么做的。但是,如果您只有数据包的一部分,则可能会从阵列的末尾运行。您可以通过创建自己的strlen()来解决这一问题,strlen()占用数组的最大长度,并在结束之前停止。只分配1025个字节并将1024个字节设置为零不是更容易、更有效吗?这样,如果strlen()返回1024,你就知道你还没有收到空终止符。我一行代码都不懂!!!,不知道那是什么语言,但我用另一种方式更新了我的第一篇文章,是一样的吗?thx,它现在工作得更好了,我会稍微调整一下,它非常聪明的方法是:我使用套接字发送和接收JSON数据。我调用recv()一次。然后我计算“{”s和“}”s。当至少有一个花括号且两个花括号的数量相等(“{”s>0)和(“{”s==“}”s)时,我知道我拥有所有数据,可以停止。
#define UPLOAD_LEN 2755
int PacketSize, recvLen;
char Size[4];
char recvBuffer[UPLOAD_LEN+1];
while(1)
{
    if(recv(Socket,Size,4,0)>0)
    {
        Size[4] = '\0';
        PacketSize = atoi(Size);
        if (PacketSize > UPLOAD_LEN || PacketSize <= 0) continue;
        recvLen = recv(Socket, recvBuffer, PacketSize, 0);
    } else recvLen = -1;
    if (recvLen > 0)
    {
        recvBuffer[recvLen] = '\0';
        ProcessData(recvBuffer);
    }
    else
    {
        closesocket(Socket);
    }
}
#include <winsock2.h>
#include <string.h>

typedef struct buffsock {
    SOCKET s;
    char* buf;
    size_t maxlen;
    size_t curlen;
} buffsock_t;

void buffsock_init(buffsock_t* bs,SOCKET s,size_t maxlen)
{
    bs->s = s;
    bs->buf = malloc(maxlen);
    bs->maxlen = maxlen;
    bs->curlen = 0;
}

void buffsock_free(buffsock_t* bs)
{
    free(bs->buf);
    bs->buf = NULL;
    bs->maxlen = 0;
    bs->curlen = 0;
    bs->s = INVALID_SOCKET;
}

/* Attempt to fill internal buffer.
 * Returns 0 if socket closed.
 * Returns number of additional bytes in buffer otherwise.
 */
int buffsock_fill(buffsock_t* bs)
{
    int bytes;
    bytes = recv(bs->s,bs->buf + bs->curlen,bs->maxlen - bs->curlen,0);
    if(bytes == SOCKET_ERROR)
        return -1;
    bs->curlen += bytes;
    return bytes;
}

/* Return up to <bytes> from buffered socket.
 * If return value 0 socket was closed.
 * If return value >0 and <bytes socket received partial message.
 */
int buffsock_bytes(buffsock_t* bs,size_t bytes,void* msg)
{
    while(bs->curlen < bytes)
    {
        int result;
        result = buffsock_fill(bs);
        if(result == -1)
            return -1; /* error on socket */
        if(result == 0)
            break;
    }
    if(bytes > bs->curlen)
        bytes = bs->curlen;
    memcpy(msg,bs->buf,bytes);
    bs->curlen -= bytes;
    memmove(bs->buf,bs->buf + bytes,bs->curlen);
    return bytes;
}

/* Implmementation of a protocol with two big-endian bytes indicating
 * msg size followed by <size> bytes of message.
 * Returns -1 if error on socket.
 * Returns -2 if partial message recv'd (shouldn't happen as long as
 * internal buffer is bigger than max message size).
 * Returns -3 if user buffer not big enough to hold message.
 * Returns size of message otherwise.
 */
int get_protocol_message(buffsock_t* bs,void* msg,size_t maxlen)
{
    int bytes;
    u_short len;
    bytes = buffsock_bytes(bs,sizeof(u_short),&len);
    if(bytes == 0)
        return 0;  /* socket closed, no more messages */
    if(bytes == -1)
        return -1; /* error on socket */
    if(bytes < sizeof(u_short))
        return -2; /* partial message */
    len = ntohs(len);
    if(len > maxlen)
        return -3; /* message exceeds user buffer */
    bytes = buffsock_bytes(bs,len,msg);
    if(bytes < len)
        return -2; /* partial message */
    return bytes;
}
int len;
char msg[256];
buffsock_t bs;
/* open a socket */
buffsock_init(&bs,sock,1024);
len = get_protocol_message(&bs,msg,sizeof(msg));