网络编程-socket通信过程

通信过程

TCP/socket通信过程分为客户端和服务器,下面分别介绍

服务器端

服务器端是被动接受连接的角色,主要有以下步骤

  1. 创建一个用于监听的套接字 socket()
    -监听:监听有客户端的连接
    -套接字:相当于文件描述符,该套接字只用来监听
  2. 将监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息) bind()
    客户端连接服务器使用的就是这个IP和端口
  3. 设置监听,监听的fd开始工作 listen()
  4. 阻塞等待,当有客户端发起连接,解除阻塞, 接受客户端的连接,得到用于和客户端通信的套接字(fd) accept()
    每有一个客户端通信,新创建一个套接字
  5. 通信
    接/发数据 recv() send()
  6. 通信结束,断开连接 close()

客户端

客户端通常主动发起连接,有以下步骤

  1. 创建一个用于通信的套接字(fd)
  2. 连接服务器,指定连接的服务器的IP和端口
  3. 连接成功,通信
  4. 通信结束,断开连接

通信过程图

上述通信步骤可用过程图表示:
在这里插入图片描述
其中建立连接指的是三次握手的过程,详情可见 TCP协议详解

套接字函数

这部分介绍上图中各个函数的具体定义。所有函数都可以通过man手册查看。
要包含的头文件:

#include <sys/types.h>
#include <sys/socket.h>

或只用一个头文件

#include <arpa/inet.h>

创建 socket()

Linux的哲学是,所有的东西都是文件。socket也不例外,就是可读可写、可控制可关闭的文件描述符。

int socket(int domain, int type, int protocol);

功能:创建一个套接字
参数:

  • domain: 协议族

    • AF_INET : ipv4
    • AF_INET6 : ipv6
    • AF_UNIX, AF_LOCAL : 本地套接字通信
  • type: 通信过程中使用的协议类型

    • SOCK_STREAM : 流式协议
    • SOCK_DGRAM : 报式协议
  • protocol : 具体的一个协议。一般写0

    • SOCK_STREAM : 流式协议默认使用 TCP
    • SOCK_DGRAM : 报式协议默认使用 UDP

返回值:

  • 成功:返回文件描述符,操作的就是内核缓冲区。
  • 失败:-1

绑定/命名 bind()

创建socket时指定了地址族,但并未指定使用该地址族的具体socket地址
将一个socket与socket地址绑定称为给socket命名。在服务器程序中,通常要命名socket,因为只有命名后客户端才知道如何连接它。而客户端不需要命名socket,采用匿名方式,使用操作系统自动分配的socket地址。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // socket命名

bind将addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数指出该socket地址长度

  • 功能:绑定,将fd 和本地的IP + 端口进行绑定
  • 参数:
    • sockfd : 通过socket函数得到的文件描述符
    • addr : 需要绑定的socket地址,这个地址封装了ip和端口号的信息
    • addrlen : 第二个参数结构体占的内存大小

监听 listen()

int listen(int sockfd, int backlog); // /proc/sys/net/core/somaxconn
  • 功能:监听这个socket上的连接
  • 参数:
    • sockfd : 通过socket()函数得到的文件描述符
    • backlog : 未连接的和已经连接的socket的最大值

接受连接 accept()

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接
  • 参数:
    • sockfd : 用于监听的文件描述符
    • addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)
    • addrlen : 指定第二个参数的对应的内存大小
  • 返回值:
    • 成功 :用于通信的文件描述符
    • -1 : 失败

发起连接 connect()

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 功能: 客户端连接服务器
  • 参数:
    • sockfd : 用于通信的文件描述符
    • addr : 客户端要连接的服务器的地址信息
    • addrlen : 第二个参数的内存大小
  • 返回值:成功 0, 失败 -1

关闭连接 close()

关闭连接实际上就是关闭该连接对应的socket
需要的头文件:

#include <unistd.h>

int close(int fd);

fd是待关闭的socket
close系统调用并非立即关闭,而是将fd的引用计数减1。当计数为0时才真正关闭

多进程程序中,一次fork系统调用默认将使父进程中打开的socket引用计数加1,因此必须在父进程和子进程中都对该socket执行close调用才能将连接关闭

猜你喜欢

转载自blog.csdn.net/MinutkiBegut/article/details/114268072