在客户端 发起连接之前,服务器端先进行初始化
- 首先初始化socket
- 执行bind函数,将自己服务能力绑定在一个总所周知的地址和端口上
bind(int fd, void * addr, socklen_t len)
-
sockaddr * addr
-
然后执行lisen,将原先的socket转化成服务器端的socket,服务器最后阻塞在accept上等待客户端请求的到来
此时服务端准备就绪,客户端需要 -
先进行初始化socket
-
再进行connect向服务端的地址和端口发起连接请求,这就是著名的TCP三次握手
一旦三次握手完成,服务端和客户端建立连接,就进入了数据传输过程
- 具体来说,客户端进程向操作系统内核发起write字节流操作,内核协议栈将字节流通过网络设备传输到服务器端,服务器端从内核得到信息,将字节流从内核读入到进程中,并开始业务逻辑的处理,完成之后,服务端再将得到的结果以同样的方式写给客户端,双向传输
当双方完成交互后,需要执行close函数,操作系统内核通过原来的链接链路向服务器端发送一个FIN包,服务器收到后执行被动关闭(半关闭状态),此时服务器执行close函数,整个链路才真正关闭。(半关闭状态下,发起close请求的一方在没有收到FIN包之前都认为链接是正常的)
socket:电话机 | bind:去开户,将电话号码和电话机绑定
connect:电话机拨号 | listen:听到电话响铃
| accept:被叫的一方拿起电话应答
write/read:互相说话 | write/read:互相说话
close:挂电话 | close:挂电话
通用的套接字地址格式
/* POSIX.1g 规范规定了地址族为2字节的值. */
typedef unsigned short int sa_family_t;
/* 描述通用套接字地址 */
struct sockaddr{
sa_family_t sa_family; /* 地址族. 16-bit*/
char sa_data[14]; /* 具体的地址值 112-bit */
};
- 地址族:表示以什么方式进行地址解析和保存,
问题:为什么本地套接字格式不需要端口号,而 IPv4 和 IPv6 套接字格式却需要端口号呢?
- 本地socket本质上是在访问本地的文件系统,所以自然不需要端口。远程socket是直接将一段字节流发送到远程计算机的一个进程,而远程计算机可能同时有多个进程在监听,所以用端口号标定要发给哪一个进程