【后台开发】【TCP协议】TCP网络编程API(套接字socket接口函数)

本文深入解析网络通信原理,介绍如何使用Socket进行网络通信。涵盖了Socket的创建、绑定、监听、连接、接受、读写及关闭等关键步骤,以及TCP的三次握手过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络中进程的唯一标识

网络层的IP地址可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(IP地址,协议,端口)就可以标识网络的进程了。

什么是socket

socket即套接字,用于描述IP地址和端口 ,是进行网络通信的API接口,通过套接字可以向网络发出请求或应答网络请求。

TCP的socket交互流程

  1. 服务器根据地址类型(ipv4、ipv6)、socket类型、协议创建socket。
  2. 服务器为socket绑定IP地址和端口号。
  3. 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时服务器的socket并没有被打开。
  4. 客户端创建socket。
  5. 客户端打开socket,根据服务器IP地址和端口号试图连接服务器socket。
  6. 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息才返回,开始接收下一个客户端连接请求。
  7. 客户端连接成功,向服务器发送连接状态信息。
  8. 服务器accept方法返回,连接成功。
  9. 客户端向socket写入信息。
  10. 服务端读取信息。
  11. 客户端关闭。
  12. 服务器端关闭。
    TCP交互流程

服务器socket和客户端socket建立连接的部分其实就是三次握手过程:
TCP三次握手

socket接口函数

1. socket函数:

socket函数原型:int socket(int domain, int type, int protocol);

socket()创建成功就返回一个socket描述符,它唯一标识一个socket。但是这个返回的描述符存在于协议族空间中,并没有一个具体地址。如果想要给它赋予一个地址,就必须调用bind()函数,否则系统就在调用connect()、listen()时自动随机分配一个端口。

2. bind()函数:

bind()函数把一个地址族中的特定地址赋给socket。

原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

  1. sockfd参数:即socket描述字,它是通过socket()函数创建来唯一标识一个sockett的,bind()函数就是将这个描述字绑定一个名字。
  2. addr参数:要绑定给sockfd的协议地址。
  3. addrlen参数:对应的是地址的长度。
  4. 返回值:成功返回0,失败返回SOCKET_ERROR。

通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来连接服务器;而客户端就不用指定,由系统自动分配一个端口号和自身IP地址组合。这就是为什么通常服务端在调用listen之前会调用bind(),而客户端就不用调用,而是在connect()时由系统随机生成一个。

3. listen和connect函数:

服务器在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务端就会收到这个请求。

listen和connect的函数原型:
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。
connect函数第一个参数为客户端的socket描述字,第二个参数为服务器的socket地址,第三个参数为socket地址长度。

客户端通过调用connect函数来建立与TCP服务器的连接。

4. accept函数:

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址;TCP客户端依次调用socket()、connect()之后就会向TCP服务器发送连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数接收请求,这样连接就建立好了,之后就可以进行网络I/O操作了。

accept函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
如果accept成功,返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

  • 注意:
    accept函数的第一参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常只创建一个监听socket描述字,它在改服务器的声明周期内一直存在;内核为每个进程创建一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。
5. read和write函数:

至此服务器与客户端已经建立好连接了,可以调用网络I/O进行读写操作了。

read()函数原型:ssize_t read(int fd, void *buf, size_t count);
read函数负责从fd中读取内容。当读取成功时,read()返回实际所读的字节数,返回0表示已经读到文件的结束了,小于0表示出错。

write()函数原型:ssize_t write(int fd, const void *buf, size_t count);
write函数将buf中的内容写入fd。

6. close函数:

close函数需要包含头文件:#include<unistd.h>
函数原型:int close(int fd);

close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0时,才会触发TCP客户端向服务器发送终止连接请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值