太原的网站搭建公司,如何做影视网站,wordpress 当前用户所有评论,wordpress 主题公园这篇文章将会编写基本的服务器网络程序#xff0c;主要讲解服务器端和客户端代码的原理#xff0c;至于网络名词很具体的概念#xff0c;例如什么是TCP协议#xff0c;不会过多涉及。
首先介绍一下TCP网络编程的两种模式#xff1a;服务器端和客户端模式#xff1a; 首先…这篇文章将会编写基本的服务器网络程序主要讲解服务器端和客户端代码的原理至于网络名词很具体的概念例如什么是TCP协议不会过多涉及。
首先介绍一下TCP网络编程的两种模式服务器端和客户端模式 首先说明一下黑色线代表状态的转换红色线表示的是数据的传输read 和 write 之间的循环表示例如读取完数据进入写入的状态写入完再进入读取的状态一直循环实现了服务器和客户端之间的通信。 首先来解释一下服务器端
int socket(int domain, int type, int protocol)
socket() 表示创建一个套接字。套接字是网络通信的基本数据结构用于定义通信协议如 TCP 或 UDP和地址族如 IPv4 或 IPv6。通过套接字服务器和客户端可以在网络上传输数据可以把套接字理解为一个编程接口利用套接字实现程序和网络的连接像是用户层和传输层TCP中间的一个抽象层有了套接字才可以向网络发送数据。
传入的内容是协议族套接字类型默认协议通常为0 返回成功返回套接字描述符失败返回-1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
bind() 表示将套接字绑定到一个特定的地址和端口。绑定的地址和端口标识服务器使客户端能够找到并连接到该服务。只有套接字还不够我还要知道是哪个主机IP发送的哪个应用程序端口发送的端口可以理解为电脑通信的入口和出口。
传入的内容是套接字描述符地址结构体的地址地址结构体大小 返回成功返回0失败返回-1。
int listen(int sockfd, int backlog)
listen() 表示将套接字转换为监听模式并设置等待连接的队列长度。当多个客户端请求连接时服务器会将这些请求加入队列按顺序处理。
传入的内容是套接字描述符队列的长度 返回成功返回0失败返回-1。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
accept() 表示等待接受客户端的连接请求接收到请求成功连接后accept() 返回一个新的套接字用于与该客户端通信而原始监听套接字则继续处理新的连接请求。
传入的内容是套接字描述符地址结构体的地址地址结构体大小的地址 返回成功返回新的套接字描述符失败返回-1
ssize_t read(int sockfd, void *buf, size_t count)
read() 表示从套接字描述符中读取数据用于接收客户端发送的消息。读取的数据存储在提供的缓冲区中。
传入的内容是套接字描述符缓冲区指针数组要读取的字节数 返回成功返回实际读取的字节数失败返回-1。
ssize_t write(int sockfd, const void *buf, size_t count)
write() 表示向套接字描述符中写入数据用于向客户端发送响应数据。
传入的内容是套接字描述符缓冲区指针数组要写入的字节数 返回成功返回实际写入的字节数失败返回-1。
int close(int sockfd)
close()表示关闭套接字描述符。
传入的内容是套接字描述符 返回成功返回0失败返回-1。 接着解释一下客户端的新出现的函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);connet()表示客户端向服务器发起连接请求。客户端告诉操作系统需要连接到哪个服务器的哪个端口。
传入的内容是套接字描述符地址结构体的地址地址结构体大小 返回成功返回0失败返回-1。 看完这些你会发现套接字描述符和文件描述符很像都可以根据描述进行写入读取和各种其他操作其实这就是UNIX系统和类UNIX系统Linux系统的抽象资源管理方式通过整数来标识系统中的资源使用统一的接口设计“一切皆文件”。 看到这里你一定有几个问题
1.为什么客户端少了bind()和listen()的操作
2.为什么connect操作指向了accept操作之后
3.地址结构体的地址addr是个什么东西
4.为什么有的函数传addr大小有的传addr大小的地址
1.对于服务器端来说服务器需要绑定到固定的端口这样客户端才能知道它对于客户端来说操作系统会在必要的时候分配临时的本地端口和地址不需要再绑定端口。
2.因为服务器端的accept函数是阻塞的等待客户端发起请求当connect发送给服务器端请求之后才会继续进行后面的读写操作。
3.addr的类型如下有两个成员分别是地址族地址和端口信息但是这不方便我们进行设置所以一般采用 sockaddr_in 这个结构最后在进行强制类型转换得到sockaddr注意这两个结构体类型大小是一样的只是结构不一样。
struct sockaddr {sa_family_t sa_family; // 地址族例如 AF_INETIPv4或 AF_INET6IPv6char sa_data[14]; // 地址和端口信息
};下面是sockaddr_in结构体类型可以清楚地看到每个成员的含义
struct sockaddr_in {sa_family_t sin_family; // 地址族通常为 AF_INETIPv4uint16_t sin_port; // 端口号16 位以网络字节序表示struct in_addr sin_addr; // IP 地址32 位char sin_zero[8]; // 保留字段填充用
};4.可以看到accept函数的addrlen参数是 addr 大小变量的地址但是connect和bind函数的addrlen参数是 addr 大小变量本身这是因为accept不知道调用者提供的 addr 缓冲区的大小可能是IPv4可能是IPv6所以需要地址地址。 我猜测可能和TCP的三次握手或者accept返回新的套接字或者客户端分配动态端口有关系而connect和bind函数都是用已知的套接字进行操作所以不会进行addr大小的改变所以可以直接传值。 这就是TCP编程的两种模式从下篇文章开始我们将学习如何编写服务器端和客户端的代码。
这就是文章的所有内容了希望对你有所帮助如有错误欢迎指出。