套接字如何在C中工作?

时间:2020-03-05 18:49:05  来源:igfitidea点击:

我对使用C进行套接字编程感到有些困惑。

我们创建一个套接字,将其绑定到接口和IP地址,并使其监听。我在上面找到了两个Web资源,并且很好理解。尤其是,我发现Unix系统下的网络编程一文非常有用。

让我感到困惑的是数据到达套接字的时间。

我们如何分辨何时到达数据包以及数据包有多大,我们是否需要自己承担所有繁重的工作?

我在这里的基本假设是数据包可以具有可变长度,因此一旦二进制数据开始出现在套接字下方,我们如何开始从该数据包构造数据包?

解决方案

回答

在套接字上进行读取时,我们告诉它要读取的最大字节数,但是如果没有那么多字节,那么它将为我们提供多少字节。由我们来设计协议,以便我们知道是否有部分数据包。例如,过去发送可变长度的二进制数据时,我会在开头放置一个int来表示期望的字节数。我会进行读取,请求读取的字节数要大于协议中可能的最大数据包的字节数,然后将第一个int与收到的字节数进行比较,然后对其进行处理或者尝试进行更多读取,直到获得d得到了完整的包装袋,具体取决于。

回答

套接字的运行级别比原始数据包更高,就像可以读取/写入的文件一样。另外,当我们尝试从套接字读取数据时,操作系统将阻塞(搁置)进程,直到它具有满足请求的数据为止。

回答

简短的答案是,我们必须承担所有繁重的工作。可能会通知我们,有可读取的数据,但我们不知道有多少字节可用。在大多数使用可变长度数据包的IP协议中,将在数据包之前添加一个头,该头具有已知的固定长度。该报头将包含数据包的长度。我们读取标头,获取数据包的长度,然后读取数据包。重复此模式(先读取标头,然后读取数据包),直到通信完成。

从套接字读取数据时,我们需要一定数量的字节。读取调用可能会阻塞,直到读取了请求的字节数为止,但返回的字节数可能少于请求的字节数。发生这种情况时,我们只需重试读取,即可请求剩余的字节。

这是一个典型的C函数,用于从套接字读取一定数量的字节:

/* buffer points to memory block that is bigger than the number of bytes to be read */
/* socket is open socket that is connected to a sender */
/* bytesToRead is the number of bytes expected from the sender */
/* bytesRead is a pointer to a integer variable that will hold the number of bytes */
/*           actually received from the sender. */
/* The function returns either the number of bytes read, */
/*                             0 if the socket was closed by the sender, and */
/*                            -1 if an error occurred while reading from the socket */
int readBytes(int socket, char *buffer, int bytesToRead, int *bytesRead)
{
    *bytesRead = 0;
    while(*bytesRead < bytesToRead)
    {
        int ret = read(socket, buffer + *bytesRead, bytesToRead - *bytesRead);
        if(ret <= 0)
        {
           /* either connection was closed or an error occurred */
           return ret;
        }
        else
        {
           *bytesRead += ret;
        }
    }
    return *bytesRead;
}

回答

因此,问题的答案在很大程度上取决于我们使用的是UDP还是TCP。

对于UDP,生活变得简单得多,因为我们可以使用所需的数据包大小调用recv / recvfrom / recvmsg(无论如何,我们都可能会从源发送固定长度的数据包),并假设是否有数据可用,它的长度是数据包长度的倍数。 (即,我们以发送方数据包的大小调用recv *,并且已设置好。)

对于TCP,为了进行解释,生活会变得更加有趣,我假设我们已经知道如何使用socket(),bind(),listen()和accept(),后者是如何获取文件描述符的方法(FD)我们新建立的连接。

进行套接字阻塞的I / O有两种方法,其中我们调用read(fd,buf,N),读取坐在那里,等待直到我们将N个字节读入buf或者非阻塞状态,其中我们必须检查(使用select()或者poll())FD是否可读,然后执行read()。

在处理基于TCP的连接时,操作系统不会关注数据包的大小,因为它被认为是连续的数据流,而不是单独的数据包大小的数据块。

如果应用程序使用"数据包"(我们正在传递的打包或者未打包的数据结构),则我们应该能够使用适当的size参数调用read(),并一次从套接字读取整个数据结构。唯一需要注意的是,要记住要对要发送的任何数据进行正确的字节排序,以防源系统和目标系统的字节序不同。这适用于UDP和TCP。

就* NIX套接字编程而言,我强烈推荐W. Richard Stevens的" Unix网络编程,第1卷"(UNPv1)和" Unix环境中的高级编程"(APUE)。前者是一本有关基于网络的编程的书,与传输无关,而后者是一本很好的全方位编程书,因为它适用于基于* NIX的编程。另外,在第1卷和第2卷中查找" TCP / IP图解"。