我对C中的套接字编程有点困惑.
您创建一个套接字,将其绑定到一个接口和一个IP地址,然后让它听.我发现了几个网络资源,并且理解得很好.特别是,我发现一篇文章在Unix系统下的网络编程非常有用.
令我困惑的是数据到达套接字的时间.
你怎么知道数据包何时到达,数据包有多大,你自己必须做所有繁重的工作吗?
我的基本假设是数据包可以是可变长度的,所以一旦二进制数据开始出现在套接字中,你如何从那开始构造数据包呢?
简短的回答是你必须自己完成所有繁重的工作.可以通知您有可读取的数据,但您不知道有多少字节可用.在大多数使用可变长度数据包的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(您可能无论如何都要从源发送固定长度的数据包),并假设数据可用,它是数据包长度的倍数.(IE你用你的发送端数据包的大小调用recv*,你已经设置好了.)
对于TCP,生活变得更有趣 - 为了解释的目的,我将假设您已经知道如何使用socket(),bind(),listen()和accept() - 后者就是你如何获得新建连接的文件描述符(FD).
有两种方法可以为套接字执行I/O - 阻塞,在其中调用read(fd,buf,N)并且读取位于那里并等待直到您将N个字节读入buf - 或非阻塞,你必须检查(使用select()或poll())FD是否可读,然后你的read().
在处理基于TCP的连接时,操作系统不会关注数据包大小,因为它被认为是连续的数据流,而不是单独的数据包大小的块.
如果您的应用程序使用"数据包"(您传递的打包或解包数据结构),您应该能够使用正确的大小参数调用read(),并一次从套接字读取整个数据结构.您必须处理的唯一警告是,在源和目标系统具有不同字节字节的情况下,记住要正确地对您发送的任何数据进行字节顺序排序.这适用于UDP和TCP.
就*NIX套接字编程而言,我强烈推荐W. Richard Stevens的"Unix网络编程,第1卷"(UNPv1)和"Unix环境中的高级编程"(APUE).第一个是关于基于网络的编程的一本书,无论传输如何,后者是一个很好的全面编程书,因为它适用于基于*NIX的编程.另外,查看"TCP/IP Illustrated",第1卷和第2卷.