C中的send(),recv()的一些EOF机制

时间:2013-02-27 15:37:26

标签: c sockets

我想知道,如果我用我的客户端做4发送(),用C语言编写,我的服务器需要读取()4次,还是第一次读取将读取所有4次发送()全部一起?

3 个答案:

答案 0 :(得分:4)

为了帮助你一点点,你基本上已经回答了你自己的问题。

你需要在“层级”中这样做,可以这么说。

客户端:

int len = strlen(Filename) + 1; //Mind the terminating 0.
send(sock, (const char *)&len, sizeof(int), 0);
send(sock, Filename, len, 0);  //Sending the filename
send(sock, &FileSize, sizeof(int), 0);
send(sock, FileBuf, FileSize, 0);

此代码将在途中发送整个数据(假设整个文件位于'FileBuf'变量中)。

服务器:

int len;
char *FileBuf, FileName[20];
recv(sock, &len, sizeof(int), 0);  //Receives the filename length. (4 Bytes)
recv(sock, FileName, len, 0);      //Receives the filename (x bytes)
recv(sock, &len, sizeof(int), 0);  //Receives the file length (again, 4 bytes)
FileBuf = new char[len];           //Creates sufficient space in memory.
recv(sock, FileBuf, len, 0);       //Receives the file into the appropriate variable.

这是绝对的准系统变体,不是很稳固,但你应该明白这一点。

更强大的方法要求您检查recv()和send()的返回值。两者都将返回已使用此调用处理的字节数。如果此金额等于'0',则表示连接已被另一端关闭。 (主要针对recv())。如果它等于-1,则表示出现了问题,您应该检查errno变量。

如果一切顺利,它等于您发送/尝试接收的确切字节数。

但是如果它不是'len'(或0或-1),你可以写一个像这样的小包装。

unsigned char Recv(int sock, void *target, int Len) {
    unsigned char *ptr = (unsigned char *)target, Ret = 0;
    int RecvBytes = 1;
    while(Len && !Ret) {
        RecvBytes = recv(sock, ptr, Len, 0);
        if(!RecvBytes) Ret = 1;
        else if(RecvBytes == -1) Ret = errno;
        else {
            Len -= RecvBytes;
            ptr += RecvBytes;
        }
    }
    return Ret;
}

此代码的作用:它一直接收,直到您收到了您期望的所有数据(Len参数)或发生错误。如果一切顺利,则返回“0”,您可以使用if(!Recv())进行检查。

另一个有用的包装函数(可以这么说的快捷方式)就是这个:

uint32_t RecvInt(int sock) {
    uint32_t Ret;
    Recv(sock, &Ret, sizeof(Ret));
    return ntohl(Ret);
}

此函数只接收一个unsigned int,并将字节顺序从网络字节顺序更正为主机字节顺序。 (网络字节顺序总是大端,主机字节顺序通常是:小端)

使用这些包装函数,代码可能会改变如下:

uint32_t len;
char *FileBuf, FileName[20];
len = RecvInt(sock);               //Receives the filename length. (4 Bytes)
Recv(sock, FileName, len);         //Receives the filename (x bytes)
len = RecvInt(sock);               //Receives the file length (again, 4 bytes)
FileBuf = new char[len];           //Creates sufficient space in memory.
Recv(sock, FileBuf, len);          //Receives the file into the appropriate variable.

答案 1 :(得分:1)

对于流套接字(例如TCP):在发送端进行了多少send()write()次呼叫没有区别。数据可以在少至一个块中返回,多达n个块,每个块1个字节(其中n是发送的字节数),或者介于两者之间的任何内容。

对于数据报套接字(例如UDP):每个recv()recvmsg()调用将返回从另一端发送的一个完整数据报。 recv()recvmsg()次呼叫的数量应与已发送的数据报数量相同。从数据报套接字读取时首选recv(),但我相信read()的行为应该相同。

答案 2 :(得分:0)

write()read()的数量不一定相同 - write()可能将所有数据写入一个部分,但在另一台计算机上{ {1}}仅设法以几个块接收它,反之亦然。这就是为什么你应该总是检查这些函数的返回值,如果只发生部分数据传输,那么继续发送/接收其余的数据。