上一篇文章我们简单讲了TCP服务端和客户端程序的编写,但是对于里面函数并没有具体的说明。接下来具体说明一下 socket 函数。
socket 函数主要用于创建套接字,它的基本形式如下:
socket 函数的第一个参数为套接字中使用的协议分类信息,成为协议族,可分为如下几类:
之前的例子中,使用的是 PF_INET 协议族,另外套接字中实际采用的最终协议信息是通过 socket 函数的第三个参数传递的。在指定的协议族范围内通过第一个参数决定第三个参数。
套接字类型指的是套接字数据的传输方式,即使用TCP还是UDP传输。
如果向 socket 函数的第二个函数传递 SOCK_STREAM , 将创建面向连接套接字。面向连接套接字具有如下特点
收发数据的套接字中具有缓冲区,通过套接字传输的数据保存在缓冲区中,因此收到数据并不意味之马上调用 recv 函数,只要不超过缓冲区的数据容量,则有可能在数据填充满缓冲后调用一次 read函数读取全部数据。也可能分多次read函数进行读取。因此调用 read 和 write 函数的次数没有太大的意义。所以说 传输的数据是不存在数据边界的。
如果缓冲区的数据满了会怎么样呢? 首先调用 read 函数读取缓冲区的部分数据,如果 read 函数的读取速度比接受的速度满,则缓冲取可能被填满。此时套接字无法再接受数据,但即使这样也不会发生数据丢失,因此传输数据的套接字将停止传输。也就是说,面向连接的套接字会根据接收端的状态传输数据,如果传输出错还会重传。
用一句话总结面向连接的套接字就是:
可靠的、按序传输的、基于字节的面向连接的数据传输方式的套接字
如果向 socket 函数的第二个参数传递 SOCK_DGRAM 参数,则创建面向消息的套接字。面向消息的套接字有如下特点:
面向消息的套接字比面向连接的套接字具有更快的传输速度,但是无法避免的数据丢失和销毁。另外,每次传输数据大小具有一定的限制,并存在数据边界。存在数据边界意味着接收数据的次数和传输次数相同,总结面向消息的套接字一句话就是:
不可靠的、不按序传递的、以数据的高速传输为目的的套接字。
下面介绍 socket 函数的最后一个参数,该参数决定最终采用的协议。前面的程序中,最后一个参数填的0,除非遇到如下情况: 同一协议族中存在多个数据传输方式相同的协议
在参数 PF_INET 指 IPv4 网络族中,
SOCK_STREAM 面向连接的数据传输。满足以上两个条件的只有 IPPROTO_TCP,
因此可以使用下面的方式创建 TCP套接字
int tcpsocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCK_DGRAM 指向的面向消息的传输方式中,满足以上条件的只有
IPPROTO_UDP, 因此可以使用下面的方式创建 UDP套接字
int udpsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
上面介绍的为 Linux 的socket函数,windows中 socket函数跟Linux中的使用是相同,唯一不同的是返回值,这里再次给出 socket 函数的声明: