一、套接字编程
TCP服务端
1️⃣ 创建套接字socket()
1 | int sockfd = socket(PF_INET, SOCK_STREAM, 0); |
2️⃣ 存储地址信息
1 | // 定义一个struct sockaddr_in类型的变量addr,用于存储地址信息。 |
②分配套接字地址bind()
1 | // 调用bind函数将创建的套接字sock绑定到指定的地址和端口。 |
③等待连接请求状态listen()
1 | listen(sockfd, 5); // 5 是请求队列的最大长度 |
④允许连接accept()
1 | int client_sock = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); |
⑤数据交换read()/write()
1 | char buffer[1024]; |
⑥断开连接close() 关闭服务器套接字
1 | close(client_sock); |
客户端套接字编程流程
①创建套接字socket()
1 | int sockfd = socket(PF_INET, SOCK_STREAM, 0); |
②设置服务器地址
1 | struct sockaddr_in server_addr; |
③连接服务器(connect)
1 | connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); |
④数据交换read()/write()
1 | write(sockfd, "Hello, Server!", 15); // 向服务器发送数据 |
⑤断开连接close() 关闭服务器套接字
1 | close(sockfd); |
客户端套接字地址信息在哪里?
网络数据交换必须分配IP和端口。 调用connect函数时,在操作系统内核 IP使用计算机的IP,端口随机
即 客户端IP地址和端口在调用connect函数时自动分配,无需调用标记的bind函数进行分配。
客户端在listen之后 close之前connect才有效
迭代服务器
普通服务器TCP的缺点:启动一次服务程序,只能给一个客户端服务。迭代服务器比较原始,它的原型可以描述成:
1 | while(1) |
基本工作流程
- 等待连接 :服务器会一直监听一个端口,等待客户端的连接。
- 接受连接 :当客户端连接时,服务器会接受连接并建立一个新的套接字与客户端通信。
- 处理请求 :服务器会处理客户端的请求,执行一些操作,或者提供一些服务。
- 关闭连接 :处理完一个客户端的请求后,服务器关闭与该客户端的连接。
- 继续等待 :服务器回到监听状态,等待下一个客户端的连接请求。
write函数和read函数
①write函数 ssize_t write(int fd, const void *buf, size_t count);
write
函数用于向文件描述符fd
所指向的文件、套接字或其他I/O设备中写入数据。
TCP底层原理
write
函数调用后并非立即传输数据,read函数调用后也并非马上接收数据。write
函数调用瞬间,数据将移至输出缓冲;read
函数调用瞬间,从输入缓冲读取数据。
A:I/O缓冲在每个套接字中单独存在。
B:I/O缓冲在创建套接字时自动生成。
C:即使关闭套接字也会继续传递输出缓冲中遗留的数据。
D:关闭套接字将丢失输入缓冲中的数据。
“客户端输入缓冲50字节,而服务器端传输了100字节。”
填满输入缓冲前迅速调用read函数读取数据,就能腾出一部分空间,问题就解决了。
其实不会发生这类问题,因为TCP会控制数据流。TCP有滑动窗口协议。
数据收发也是如此,因此TCP中不会因为缓冲溢出而丢失数据。
但是会因为缓冲而影响传输效率。
TCP内部原理
TCP通信的三大步骤
- 三次握手建立连接;
- 开始通信,进行数据交换;
- 四次挥手断开连接;
利用TCP三次握手进行攻击。
断开连接有可能卡在中间两次发数据包的地方。
UDP编程
UDP基本原理
4层TCP/IP模型中,第二层传输层分为TCP和UDP。
只考虑可靠性,TCP比UDP更好。但UDP在结构上比TCP更简洁。UDP不会发送类似ACK的应答消息,也不会想SEQ那样给数据包分配序号。因此UDP的性能有时比TCP高出很多。
为了提供可靠的数据传输服务,TCP在不可靠的IP层进行流控制,而UDP就缺少这种流控制机制。
TCP的速度无法超过UDP,但在收发某些类型的数据时有可能接近UDP。例如,每次交换的数据量越大,TCP的传输速率越接近UDP的传输速率。
TCP比UDP慢的原因
① 收发数据前后进行的连接设置及清除过程。
② 收发数据过程中为保证可靠性而添加的流控制。
UDP 服务端
UDP 服务器/客户端不像TCP那样在连接状态下交换数据,因此与TCP不同,无需经过连接过程。也就是说,不必调用TCP连接过程中调用的listen函数和accept函数。UDP中只有创建套接字的过程和数据交换的过程。
UDP的服务端和客户端都只需要一个套接字,而TCP中,套接字之间是一一对应的关系。若要向10个客户端提供服务,则除了守门的服务器套接字外,还需要10个服务器端套接字。
UDP套接字绑定本地的IP地址和端口号,这个套接字就可以接受来自任何主机发送到该端口的数据报。
创建好TCP套接字后,传输数据时无需再添加地址信息。但是UDP套接字不会保持连接状态(UDP套接字只有简单的邮筒功能),因此每次传输数据都要添加目标地址信息。这相当于寄信前在信件中填写地址。填写地址并传输数据时调用的UDP相关函数。
1 |
|
1 |
|
UDP相关的函数
DDos攻击大多利用UDP
发生地址分配错误(重点)
客户端是connect,所以不会出现bind failed,因为有几万个端口可以用,所以connect失败很难
I/O缓冲区大小
TCP_NODELAY
监控键盘的输入
Linux系统编程:进程
并发服务器的实现方法
使其同时相所有发起请求的客户端提供服务,以提高平均满意度。
而且,网络程序中数据通信时间比CPU运算时间占比更大,因此,向多个客户端提供服务是一种有效利用CPU的方式。
- 多进程服务器:通过创建多个进程提供服务。
- 多路复用服务器:通过捆绑并统一管理I/O对象提供服务。
- 多线程服务器:通过生成与客户端等量的线程提供服务。
进程:占用内存空间正在运行的程序 就是进程
从操作系统的角度来看,进程是程序流的基本单位,若创建多个进程,则操作系统将同时运行。有时候一个程序运行过程中也会产生多个进程。