杂项
在win端要 WSAStartup(MAKE_WORD(2.2),&wsaData) WSACleanup()
1.网络地址分类
A 0 大型网络
- 网络号:1 字节(8 位),首位固定为
0
- 主机号:3 字节(24 位)
- 可用网络数量:( 2^7 - 2 ) = 126 个
- 每个网络的可用主机数量:( 2^{24} - 2 ) ≈ 1677 万个
B 10 中型 学校
C 110 小型 家庭
D 1110 用于多播Multicast
E 1111 实验地址
127.0.0.1 本机回环地址 测试网络程序
0.0.0.0 一台主机上的所有网络接口或所有网络
255.255.255.255 向局域网中所有主机发送广播消息
2.地址信息的表示
sockaddr_in
sin_family
sin_port
sin_addr INADDR_ANY(自动获取运行的IP地址)
3.地址转化
大端,小端序
htos
inet_addr(const char* s) 字符转网络字节序的网络地址
char * inet_ntoa(struct in_addr adr) 数字地址转字符指针
4.TCP的半关闭
只关闭流的一半
shutdown 可以断开输入/输出流 可以在发送数据后关闭输出流
调用close 同时关闭I/O流
5.域名解析
gethostbyname 域名获取IP
gethostbyaddr IP获取域名
6.套接字的多种选项
协议层+选项名
getsockopt
setsockopt
查看/更改套接字输入输出缓存区,套接字的类型
Binding Error 服务端强行中止,如CTRL+C ,重新在同一个端口运行就会BindError ,要等待几分钟才可以
Time wait: 先中止(传输FIN消息的主机)的一方会进入time_wait状态 ,如果服务器故障,要快速重启,那么必须等待一段时间 如果网络延迟丢包,wait状态可能还会延长
解决方法:更改套接字选项, REUSE ADDR 状态,默认为0,让处于time_wait状态下的套接字的端口重新分配给新的套接字
TCP_NODELAY
nagle算法 一应一答,收到上一次的ACK,才会发送下一次数据
传输大文件可以禁用,提高传输的速度
多进程服务器
1.fork函数
fork出的是文件描述符,记得关闭,不然要等待两个fd都销毁才能销毁套接字,即不能关闭套接字
I/O分离:通过fork,主进程为来accept,子进程来read和write
while()
{
accept
fork
子:close server_fd read/write
主:
close client_fd
}
2.僵尸进程
僵尸进程(Zombie Process)是指在操作系统中已经完成了执行,但其父进程尚未调用wait()
或waitpid()
来获取其终止状态的子进程。当一个进程结束时,操作系统会保留该进程的一些基本信息,包括进程ID(PID)、退出状态等,以供父进程查询。而如果父进程没有主动调用上述函数来检索该进程的状态,那么这个进程的信息就会一直存在于操作系统的进程表中,成为僵尸进程。
ps 查看进程
Z的为僵尸进程
kill命令其实是给对应的进程默认发送sigterm信号。
可以想办法它其它进程去回收僵尸进程的资源,这个进程就是 init 进程。
可以直接杀死父进程,init 进程就会很善良地把那些僵尸进程领养过来,并合理的回收它们的资源,那些僵尸进程就得到了妥善的处理了
僵尸进程不可以被kill因为已经退出,可以kill父进程,让init进程来接管
wait/waitpid
signal(信号,信号处理函数 ) SIG-alarm/int/chld
alarm(s) 产生alarm信号
更稳定的 sigaction 向操作系统注册消息及处理函数,有消息时会回调我们设置的信号处理函数
进程间的通信
两个进程可以同时范围的内存空间
管道通信:
单向通信,会阻塞。可以创建两个管道
PIPE( [2] )匿名
mkfifo 命名
I/O复用
一个线程同时处理和检测多个I/O
Select函数
Linux下:
fd_zero
fd_set 注册 位数组
fd_crl 清除
fd_isset 查找fd的信息
可以设置超时时间
select返回发送事件的文件描述符数,接着使用for循环使用FD_ISSET检测copy_set哪个文件描述符发送了事件。
在win端的fd_set是一个结构体,count+数组的组合,因为win端得到的是句柄,没有规律,而linux返回的fd是有规律的
多种I/O函数
send/recv 在最后的flag设置可选项,如检测 MAG_PEEK,OOB紧急数据等。
MSG_OOB发送紧急数据 在与督促接受发尽快的接收数据
fcntl可以进行设置
检测输入,输出缓存
MSG_PEEK |MAG_DONTWAIT选项
可以以不阻塞的方式检测缓冲区是否有数据,且不会读出缓冲区的数据,检测到后再去read/write有数据在去读写
readv/writev函数可以接收多个I/O缓冲区和将多个缓冲区的数据发送,减少I/O的调用的次数
多播 multicast UDP
加入多播组,D类的IP地址 1110 开头 ,可以接收到多播数据
setsockopt 设置TTL字段的生存时间
广播
同一个网络中传输数据
基于Linux的编程
标准I/O
优点:移植性+ 缓冲区提高性能 缺点:需要需要频繁调用fflush 且返回的是FILE*指针而不是文件描述符
fopen
fclose
fputc
fputs
fgetc
fgets
文件描述符的复制和半关闭
文件指针的问题:读文件指针和写文件指针指向同一个文件描述符,销毁一个文件指针,文件描述符就被销毁,套接字也就被销毁
解决方法:
使用dup/dup2函数来复制文件描述符,题目都指向同一个文件,只有两个文件描述符被销毁,套接字才被销毁
文件指针指向的是不同的文件描述符,不同的文件描述符指向同一个套接字
epoll
select优点:兼容性+客户端接入少可以用
epoll_create 创建一个epoll_event结构体
epoll_ctrl
epoll_wait
水平触发(条件触发LT) 边缘触发(垂直触发)ET
默认水平触发,
改为边缘触发要更改套接子为非阻塞且要循环读取数据,当返回-1时,还要检测是否为全局变量 error 是否为EAGIN,表示缓冲区的数据读取完毕,不算错。
多线程服务端
线程创建
pthread_create 编译添加-lpthread链接线程库
pthread_join等待线程返回
C++11 join win:waitforsigalobject
线程同步
互斥量
声明互斥量pthread_mutex_t mutex;
pthread_mutex_init/destory/lock/unlock
信号量semaphore
sem_init/destory/post(v操作)/wait(p操作)
销毁线程
pthread_join
pthrad_detach
分离后的线程不可以被 pthread_join
线程被分离,无法获取其退出状态,因为线程的资源会在它终止时自动释放
pthread_exit
pthread_exit(result); // 退出线程并传递返回值
线程在调用 pthread_exit
后不再需要处理任何资源(如文件描述符或内存),可以让操作系统自动清理它们,而不必手动调用 free()
。
pthread_join
配合使用:通常,pthread_exit
和 pthread_join
是配套使用的,用于确保线程间的同步以及获取线程的返回值。
基于windowns的编程
内核对象
操作系统记录和维护每种资源的相关结构体信息,如线程,进程,套接字等都属于内核对象。
线程的创建
CreateThread(不推荐使用)
_beginthrad /ex _endthread/ex
内核对象的两种状态: signaled/non-signaled
通过waitforsingleobject/MutilpleObject函数,可以检测检内核对象的状态
线程同步
用户模式,限制访问物理设备,限制内存访问区域
和内核模式,不会限制访问内存和物理设备,权限高
用户模式的同步:速度快,无需切换到内核模式
用户模式的同步
用户模式同步指的是那些在用户模式下执行的同步机制,不涉及内核态的切换,因此它们的性能通常较好,开销较小。这些同步机制在用户空间中完成,不需要进行内核调用,也不会引发上下文切换。
- 用户模式同步机制非常适合轻量级的同步操作,如对简单数据结构的访问或低冲突的场景。
- 临界区是一个用户模式的同步机制,使用
InitializeCriticalSection
、EnterCriticalSection
和LeaveCriticalSection
等函数来控制对共享资源的访问。 - 临界区是轻量级的,当竞争不激烈时,线程仅在用户模式下等待,性能优于内核模式的同步机制。但如果多个线程频繁竞争同一资源,临界区会通过内核模式的事件对象(Event)进行进一步的同步,可能会引发内核态切换
内核模式的同步
常见的内核模式同步机制
- 互斥体 (Mutex):
-
- 互斥体是一个内核对象,允许多个进程或线程安全地访问共享资源。它比临界区更加重量级,因为它总是需要内核态的切换。
- 信号量 (Semaphore):
-
- 信号量是另一个内核同步对象,允许一个或多个线程访问有限数量的资源。
- 事件 (Event):
-
- 事件对象用于线程之间的信号传递,一个线程可以等待一个事件对象的状态改变(有信号或无信号),这通常用于线程同步或线程间通信。
- 等待函数:
-
WaitForSingleObject
和WaitForMultipleObjects
等函数用于等待内核对象(如互斥体、信号量或事件)进入有信号状态,这些函数总是涉及内核态切换。
互斥量
信号量
事件 event
用户模式与内核模式同步的区别
特性 | 用户模式同步 | 内核模式同步 |
性能 | 高,开销小 | 低,开销大 |
上下文切换 | 无 | 有 |
实现方式 | 完全在用户模式下执行 | 需要切换到内核模式 |
适用范围 | 线程内或同一进程内 | 跨线程或跨进程 |
适用场景 | 轻量级的同步 | 复杂的同步或跨进程 |
异步通知I/O模型
重叠I/O
IOCP
I/O Completion Ports (IOCP) 是 Windows 提供的一种高效的异步 I/O 模型,广泛应用于高性能服务器开发中。IOCP 允许应用程序在多个线程上处理大量并发 I/O 请求,而不会因线程调度或上下文切换产生大量开销。
总结
CreateIoCompletionPort:创建和管理完成端口,关联 I/O 句柄与完成端口。
GetQueuedCompletionStatus:检索完成的 I/O 操作,处理完成的 I/O 请求。
PostQueuedCompletionStatus:将自定义的完成状态放入完成端口,通知线程执行任务。
通过合理利用这些函数,开发者可以构建高效的 I/O 密集型应用程序,充分发挥多核 CPU 的性能优势。
异步函数
acceptEx
ConnectEx
WSASend
WSARecv
WSASendTo
WSARecvFrom