TCP/IP网络编程 - 读书笔记

杂项

在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_exitpthread_join 是配套使用的,用于确保线程间的同步以及获取线程的返回值。

基于windowns的编程

内核对象

操作系统记录和维护每种资源的相关结构体信息,如线程,进程,套接字等都属于内核对象。

线程的创建

CreateThread(不推荐使用)

_beginthrad /ex _endthread/ex

内核对象的两种状态: signaled/non-signaled

通过waitforsingleobject/MutilpleObject函数,可以检测检内核对象的状态

线程同步

用户模式,限制访问物理设备,限制内存访问区域

和内核模式,不会限制访问内存和物理设备,权限高

用户模式的同步:速度快,无需切换到内核模式

用户模式的同步


用户模式同步指的是那些在用户模式下执行的同步机制,不涉及内核态的切换,因此它们的性能通常较好,开销较小。这些同步机制在用户空间中完成,不需要进行内核调用,也不会引发上下文切换。

  • 用户模式同步机制非常适合轻量级的同步操作,如对简单数据结构的访问或低冲突的场景。

  • 临界区是一个用户模式的同步机制,使用 InitializeCriticalSectionEnterCriticalSectionLeaveCriticalSection 等函数来控制对共享资源的访问。
  • 临界区是轻量级的,当竞争不激烈时,线程仅在用户模式下等待,性能优于内核模式的同步机制。但如果多个线程频繁竞争同一资源,临界区会通过内核模式的事件对象(Event)进行进一步的同步,可能会引发内核态切换

内核模式的同步

常见的内核模式同步机制

  • 互斥体 (Mutex)
    • 互斥体是一个内核对象,允许多个进程或线程安全地访问共享资源。它比临界区更加重量级,因为它总是需要内核态的切换。
  • 信号量 (Semaphore)
    • 信号量是另一个内核同步对象,允许一个或多个线程访问有限数量的资源。
  • 事件 (Event)
    • 事件对象用于线程之间的信号传递,一个线程可以等待一个事件对象的状态改变(有信号或无信号),这通常用于线程同步或线程间通信。
  • 等待函数
    • WaitForSingleObjectWaitForMultipleObjects 等函数用于等待内核对象(如互斥体、信号量或事件)进入有信号状态,这些函数总是涉及内核态切换。

互斥量

信号量

事件 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

  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值