socket(套接字)
源于UNIX,被BSD发扬光大
- 实际上是进程与进程之间的通信方式,socket是进程间通信的接入点
- 基于BSD的POSIX标准
- 万物皆文件的泛型,在Linux中可以像操作文件一样操作socket
- 套接字描述符的本质是文件描述符
- 可以对套接字进行close,dup2,read,write,select等操作
- 字节序的问题,大端和小端
socket()函数
int socket(int protofamily,int type,int protocol);
- 协议族(protocol family),一般使用PF_INET
- 套接字类型(type)
- SOCK_STREAM,面向连接的套接字,可以比喻成两个工人在传送带的两头传递东西,是一种可靠的,按序传递的,基于字节的面向连接的数据传输方式的套接字
- 传输过程中数据不会消失
- 按序传输数据
- 传输的数据不存在数据边界
- 套接字连接必须一一对应
- SOCK_DGRAM,面向消息的套接字,可以比喻成高速传输的快递,不可靠的,不按序传输的,以数据的高速传输为目的的套接字
- 强调快速传输而非传输顺序
- 传输的数据可能丢失也可能损毁
- 数据的传输有数据边界
- 限制每次传输的数据大小
- SOCK_STREAM,面向连接的套接字,可以比喻成两个工人在传送带的两头传递东西,是一种可靠的,按序传递的,基于字节的面向连接的数据传输方式的套接字
- 计算机间的通信协议(protocol)
socket()会返回一个socket描述符,类似于文件描述符,用于对socket进行操作 - protofamily:即协议域,又称为协议族,它决定了socket的地址类型,在通信中必须采用对应的地址类型,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址,常用的协议族有AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等
- type:socket类型,常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等
- protocol:采用的协议,用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议
- type和protocol不可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议
- 当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口
- inet_pton函数需要包含头文件arpa/inet.h
- 当使用ctrl+c结束服务器端时,再次运行服务器bind()函数会出现地址已经被使用的错误,它是由TCP套接字TIME_WAIT状态引起,该状态会在套接字关闭后保留几分钟,在该状态退出后,该地址才能被重新使用,不要使用ctrl+z退出,要使用ctrl+c退出
bind()函数
int bind(int socket,const struct sockaddr* addr,socklen_t addrlen)
bind()函数用于将地址族中的特定地址赋给socket
sockfd:即socket描述符,是socket的唯一标识
addr:指向绑定给sockfd的协议地址,这个地址结构根据地址创建socket时的地址协议族的不同而不同
addrlen:对应地址的长度
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct</