《TCPIP网络编程》阅读笔记

《TCPIP网络编程》阅读笔记,第1张

《TCP/IP网络编程》阅读笔记 第一部分开始网络编程 Linux编译基本命令

gcc hello.c -o hello

-o 是用来指定可执行文件名的可选参数

Linux的文件 *** 作

在Linux世界里,socket也没认为是文件的一种,因此在数据传输过程中自然可以使用文件i/o的相关函数

而在windows环境下是进行区分的

打开文件 *** 作

#include
#include
#include

int open(const char *path, int flag);
//--->成功是返回文件描述符,失败返回-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7DLZS7x-1641215230584)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220101190724882.png)]

关闭文件

int close(int fd);
//--->成功时返回0,失败-1
/

注意:此函数定义中的size_t是通过typedef生命的unsigned int类型。对于ssize_t来说,size_t前面多加的s代表signed,是signed int 类型。

在项目中为了给基本数据类型赋予别名,一般会添加大量的typedef声明。而为了与程序员定义的新数据类型加以区分, *** 作系统定义的数据类型会添加后缀_t。

接受文件的数据(read)

#include

ssize_t read(int fd,void *buf, size_t nbytes);
//--->成功时返回接受的字节数(但遇到文件结尾则返回),失败时返回-1.
//参数和write参数类似
windows套接字

进行winsock编程时,首先必须调用WSAStartup函数,设置程序中用到的Winsock版本,并初始化相关版本的库(linux)下不需要这么做

#include
int WSAStartup(WORD wVersionRequested, LPWSADATA IpWSAData);
//--->成功返回0,失败返回非零的错误代码值
//wVersionRequested  程序员用到的Winsock版本信息
//IpWSAData WSADATA结构体变量的地址值

MAKEWORD(1,2);
MAKEWORD(2,2);
//上述两个是宏函数,用于渐变的构造WORD类型的版本信息

第二个参数LPWSDATA是WSADATA的指针类型,因此winsock有如下的编程公式

int main(int argc,char* argv[]){
    WSADATA wsaData;
    ...
    if(WSAStartup(MAKEWORD(2,2), &wsaData)!=0)
        ErrorHanding("WSAStartup() error!");
    ....
    WSACleanup();//成功时返回0,失败是返回socket_error
}
文件I/O与标准I/O的区别

参考链接(12条消息) 底层文件I/O和ANSI标准I/O的区别_云鹤起舞的博客-CSDN博客_底层文件

简单来说文件I/O和 *** 作系统有关,通过系统调用来直接 *** 作文件,没有缓存

而标准I/O在文件I/O的基础上进行了封装,先进行缓冲区的读写,然后在通过系统调用写入文件

套接字详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AqjOiMEA-1641215230585)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220101195221764.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gyo4y9HF-1641215230586)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220101195418603.png)]

套接字类型

SOCK_STREAM面向连接的套接字,面向连接的套接字不存在数据边界。

SOCK_DGRAM面向消息的套戒指

服务器端常见初始化过程

linux

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0R0gVQo-1641215230586)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220101203236425.png)]

Windows

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVws3WpN-1641215230586)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220101203414569.png)]

UDP连接

udp的发送数据函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iKVa77wX-1641215230587)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102171941169.png)]

udp的接受数据函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b7bnegj5-1641215230587)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102172044571.png)]

unp存在数据边界因此输入函数的调用次数,应该和输出函数的调用次数完全一致,这样才能保证结束到全部发送的数据。

未连接的udp套戒指每次sendto大致分为如下三个阶段

1 向udp套接字注册目标IP和端口号

2 传输数据

3 删除UDP套接字中注册的目标地址信息

已连接的udp套接字可以不用每次sendto时候注册目标端口和IP传送玩之后在删除UDP。可以用write,read函数进行通讯,但并不代表建立了tcp一样的连接。

TCP的半关闭

tcp断开连接的过程可能发生预想不到的情况,因此应准确掌握

close和closesocket是完全断开,完全款开无法传递数据,也无法接收数据

shutdown(Linux)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4X9RbNrs-1641215230587)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102191302495.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxyKBORN-1641215230588)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102191311404.png)]

shutdown(Windows)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x7EUslz0-1641215230588)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102192105729.png)]

上面第二个参数知识名称不同,在LINUX和WINDOWS中他值都是一样的,断开输入流是0断开输出流是1断开io流是2

域名转换函数

利用域名获得ip地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D65KV8YI-1641215230588)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102193325218.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZ2dj95a-1641215230589)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102193419218.png)]

利用ip地址获得域名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LTtOxuI-1641215230589)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102193917412.png)]

套接字的多种可选项

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aI6gxL3p-1641215230589)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102194225423.png)]

可选项的读取和设置

读取

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dakHaMnv-1641215230590)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102194347097.png)]

设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i6BBjg8k-1641215230590)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102194401156.png)]

Time-wait状态

tcp连接下,任何一方通过强制断开连接,都会使socket进入time-wait状态,此时端口是正在使用状态,因此服务器强制断开连接会导致下次启动服务器的时候会bind失败(客户端由于每次都是随机的端口号,因此很少有这类问题出现)

解决办法就是在套接字中更给SO_REUSERDDR的状态,调整参数,可将TIME_Wait状态下的套接字端口重新分配给新的套接字。设置为1既可以。

nagle算法

nagle算法默认使用,最大限度地进行缓冲,直到收到ACK。不适用nagle算法将对网络流量产生负面影响。

**但有些时候不使用nagle算法反而有更快的传输速率。最典型的是传输大文件数据。**将文件传入输出缓冲不会花费太多时间,因此,即使不使用nagle算法,也会在装满输出缓冲时传输数据包。这不仅不会增肌数据包的数量,反而会在无需等待ack的前提下连续传输,因此可以大大提高传输速度。

禁用nagle算法只需要讲套接字的可选项tcp_nodelay改为1即可

int opt_val=1;
setsocketopt(sock, IPPROTO_TCP,TCP_NODELAY, (void *) &opt_val,sizeof(opt_val));
多进程服务端

具有代表性的并发服务器端实现模型和方法。

1 多进程服务器:通过创建多个进程提供服务

缺点,开销很大,大量的运算和内存空间,相互间的数据交换也需要相对复杂的方法IPC

2 多路复用服务器: 通过捆绑并统一管理I/O对象提供服务。

3 多线程服务器: 通过生成与客户端等量的线程提供服务。

期中1多进程服务器不支持windows只有在linux下才能实现多进程

多进程

通过fork来创建此进程,父进程返回子进程的ID之后fork后面的代码复制到子进程中(包括fock代码)子进程返回0。子进程退出后必须把函数退出返回值传输父进程, *** 作系统才会把子进程完全杀掉。否则会变成**僵尸进程。**父进程需要主动向 *** 作系统请求子进程的退出返回值。有如下函数

wait[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuL3GC1w-1641215230590)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102205321423.png)]

waitpid函数

wait函数没有终止的子进程会进入阻塞状态。会引起程序阻塞,还可以考虑调用waitpid函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGM4sArF-1641215230591)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102205450276.png)]

信号处理

上面的过程固然可以,但是如果子 *** 作系统在子进程销毁时告诉父进程是不是更好?那就用到了信号处理机制

。。。。。。略。

基于多任务的并发服务器linux多进程版本,见参考书《TCP/IP网络变成》第173页

分割i/o设计实际上,在一个进程内同时进行数据的收发逻辑需要考虑更多的细节。程序越复杂,这种区别越明显,因此可以在父进程中辫子额接收数据的代码,子进程中子需要编写发送数据的代码即可实现I/O分割。

进程间通讯详见《TCP/IP网络变成》第183页

!!!复杂功能的服务端程序并不是用的进程和管道,有两种更为强大的模型

I/O复用

select函数可以将多个文件描述符集中到一起统一监视。

select函数的调用方法和顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpBI1cv1-1641215230591)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102211732210.png)]

设置文件描述符:也就是把不同的监视项分类,把同一类别的文件描述符集中在一起。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZgSrkCNH-1641215230591)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102211904004.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXxGM7pE-1641215230591)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102212006488.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQB4HGPW-1641215230592)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102212130008.png)]

设置检查(监察)范围及超时

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYHVhtTn-1641215230595)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220102212201665.png)]

也就是说,监视范围为最大的文件描述符值加一在传递到select函数的第一个参数上即可。

超时时间是一个timeval结构数组,有两个参数 tv_sec秒,tv_usec毫秒。然后把该结构体的地址值传递到select函数的最后一个参数即可。第二到第四个参数分别传入声明的3个fd_sed型变量(分别向其注册文件描述符信息)的地址。

调用select函数后查看结果

如果select函数的返回值大于0说明相应数量的文件描述符发生了变化(注意是相应数量的文件描述符,不是对应的文件描述符)发生变化后,把向其传递的fd_set变量中原来为1的所有位变成了0,发生变化的文件描述符对应的位置除外。

以下为采用I/O复用的服务端程序(回声程序)

#include
#include
#include
#include
#pragma comment(lib, "ws2_32")
#define BUF_SIZE 1024
void ErrorHandling(char *message);

int main(int argc,char *argv[])
{
    WSADATA wsaDara;
    SOCKET hServSock,hClntSock;
    SOCKADDR_IN servAdr,clntAdr;
    TIMeval timeout;
    fd_set reads,cpyReads;

    int adrSz;
    int strLen,fdNum,i;
    char buf[BUF_SIZE];

    if(argc!=2){
        printf("Usage: %s n",argv[0]);
    }
    //使用windows网络编程相关库
    if(WSAStartup(MAKEWORD(2,2),&wsaDara)!=0)
        ErrorHandling("WSAStartup() error!");
    //创建服务端的socket
    hServSock = socket(PF_INET,SOCK_STREAM,0);
    memset(&servAdr,0,sizeof(servAdr));
    //设置服务端的端口 ip 协议信息
    servAdr.sin_family=AF_INET;
    servAdr.sin_port=htons(atoi(argv[1]));
    servAdr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

    if(bind(hServSock,(SOCKADDR*)&servAdr,sizeof(servAdr))==SOCKET_ERROR)
        ErrorHandling("bing() error");
    if(listen(hServSock,5)==SOCKET_ERROR)
        ErrorHandling("listen() error");
    
    //设置set数组(初始化)
    FD_ZERO(&reads);
    //把服务端套接字句柄注册在set数组里面
    FD_SET(hServSock,&reads);

    while(1){
        //赋值以下set数组,以备select监听到修改后还原注册的socket句柄
        cpyReads=reads;
        timeout.tv_sec=5;
        timeout.tv_usec=5000;

        //调用select函数
        if((fdNum=select(0,&cpyReads,0,0,&timeout))==SOCKET_ERROR)
            break;
        
        if(fdNum==0)
            continue;
        //循环查看已注册的socket句柄时候有变化
        for(i=0;i 
多种I/O函数 
linux下的send recv函数 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d3OlxQPG-1641215230596)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103152903766.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vZpiyYTi-1641215230597)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103152915133.png)]

send与recv函数的最后一个参数是发送数据时的可选项。用位或运算同时传递多个信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sfeUTq37-1641215230597)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103153039634.png)]

设置了MSG_PEEK可选项并调用recv函数时候,即使读取了输入缓冲的数据也不会删除。通常与MSG_DONTWAIT可选项同时使用,没有信息的时候不会阻塞,有信息的时候不会删除输入缓冲区的数据。

readv & writev 函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jFiaDH0p-1641215230597)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103154458196.png)]

使用场景:实际上,能使用该函数的所有情况都可以使用。比如需要传输或者接受的数据位于多个不同的缓冲(数组)时,可以考虑使用这两个函数。而有些服务器为了提高效率,禁用Nagle算法,通过write能分别发送了3个数据包,采用writev函数很有可能将所有的数据一次性写入输出缓存只传输一个数据包。

windows下的紧急情况传输及接受

紧急数据的传输,和linux相同,发送数据的时候设置对应的可选项即可。

紧急数据的接受。利用select监视发生异常的套接字来实现紧急消息的接受(linux下是通过信号处理机制实现的)

**!!! windows下没有writev和readv实现多个缓冲区数据的收发!!! **

!!! 需要用到重叠I/O (在后面) !!!

多播

理论上支持多播的路由器既可以完成多播,但是因为拥塞控制可能故意阻止多播。因此为了在不支持多播的路由器中完成多播通信,也会使用隧道技术。我们只讨论支持多播服务的环境下的编程方法。

路由和ttl

为了传递多播数据包必须设置TTL

int send_sock;int time_live=64;...send_sock=socket(PF_INET,SOCK_DGRAM,0);setsocktop(send_sock ,IPPROTO_IP,IP_MULTICAST_TTL,           (void*)&time_live,sizeof(time_live));

加入多播组

通过set客户端socket的可选项既可以加入多播组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJB6bwME-1641215230597)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103160910189.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x1di3r7W-1641215230598)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103161107792.png)]

多播发送与接受的过程

多播发送者需要把数据发送到多播组地址上的对应端口那里,接收者bind自己的socket后加入多播组,(自己必须要使用和多播地址对应的端口相同的端口号)。然后接受多播数据。

广播
  • 直接广播(除了网络地址外,全部设置1)
  • 本地广播(255.255.255.255,向本主机所在网络的所有主机传输数据)

数据通信中使用的IP地址时与UDP示例的唯一区别。默认生成的套接字不支持接受广播数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A8s7adDV-1641215230598)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103162550589.png)]

第二部分Linux特有的网络编程

详情看《TCP/IP网络编程》P246页

套接字和标准IO

标准IO的优点

标注IO具有良好的移植性

标准IO函数可以利用缓冲提高性能

标准IO的缺点

不容易进行双向通信

有时可能频繁的调用fflush函数

需要以FILE结构体指针的形式返回文件描述符

关于IO流分离的其他内容

分离IO的两种方法

第一种时通过fork函数复制出一个文件描述符,比区分输入和输出中使用的文件描述符。

第二种方法时两次fdopen函数的调用,创建了读和写模式的不同file指针。

分离IO流的好处

  • 通过分开输入过程和输出过程降低实现难度
  • 与输入无关的输出 *** 作可以提高速度
  • 为了将file指针按照读写模式加以区分
  • 通过区分IO缓冲提高缓冲性能

Linux下可以把文件描述符的读写分离(通过fdopen)

但这种情况下衍生出一个问题就是怎么进行socket的半关闭,如果直接关闭对应的file指针,都会关闭文件描述符,因此采用的办法就是复制一次文件描述符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZqVKN9fD-1641215230598)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103165004154.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-In3fMXQO-1641215230598)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103165204426.png)]

无论复制出多少文件描述符都应该调用shutdown函数发送eof进入版关闭状态。

优于select的epoll

select的缺点

  • 首先就是调用select函数后常见的针对所有文件描述符的循环与及
  • 更严重的是每次调用select函数时都需要向该函数传递监视对象的信息

传递监视对象的信息的含义是:每次调用select函数时向 *** 作系统出啊你监视对象的信息,这一步无法优化,并且应用程序向炒作系统传递信息会对程序照成很大的负担

select的优点

  • 大多出 *** 作系统都支持select函数
  • 服务端接入者比较少的时候并不会感到明显的变慢
  • select的程序兼容性更高

针对select的缺点进行改变

仅向 *** 作系统传递一次监视对象,监视范围或内容发生变化时只通知发生变化的事项。

linux支持的方式时epoll,windows支持的方式时IOCP

windows下的网络编程特点 线程的相关内容 线程的使用

线程的创建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2xTHCyCN-1641215230599)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103181725827.png)]

如何知道线程什么时候执行完

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYpeViud-1641215230599)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103182359275.png)]

互斥量的创建和使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jFNs05hz-1641215230599)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103184020888.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q6xGwSIE-1641215230599)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103185113435.png)]

信号量的创建和使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4HfOEaIt-1641215230600)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103185257567.png)]

上锁相当于调用wait函数

线程的销毁和多线程并发服务器端的实现

linux线程并不是在线程main函数返回时自动销毁因此需要手动销毁,否者会一直占用内存

  • 调用pthread_join函数(不仅会等待线程结果,还会销毁线程,但会照成阻塞)
  • 调用pthread_detach函数(不会引起线程进入阻塞状态,调用后不能再针对相应的先册灰姑娘调用pthread_detach函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rSGRkAyr-1641215230600)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103185910440.png)]

Windows平台下线程的使用

非显示创建线程的程序是“单一线程模型的应用程序”

显示创建线程的程序是”多线程模型的应用程序“

因此main函数实际上是线程完成的。

线程的创建和使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OnTueL3a-1641215230600)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103191943729.png)]

不同于linux Windows线程在首次调用的线程main函数返回时销毁。还有其他方法可以终止线程,但最好的方法就是让线程main函数终止。

如果线程要使用C/C++标准函数,需要通过如下的方法创建线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vwisw7vl-1641215230600)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103192218351.png)]

查看内核对象的状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOZWIbv4-1641215230600)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103193130226.png)]

该函数在发生事件(变为signaled状态)返回时,有时会把相应内核对象再次改编为non-signaled状态。

接下来的函数可以查看多个内核对象状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pvUeoIxR-1641215230601)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103193314959.png)]

线程同步

线程同步分为两个,一个是用户模式下同步,一个是内核模式同步

用户模式下同步最大的有点是速度快,使用方法相对简单,但是存在一定局限性

基于用户模式下的同步

初始化[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UK3zXVEA-1641215230601)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103202307475.png)]

获得该函数的参数类型的对象的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Th7tJ2Cz-1641215230601)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103202403026.png)]

内核模式的同步方法–互斥量

互斥量对象的函数创建互斥量[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PZkxzBYL-1641215230601)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103202535614.png)]

销毁互斥量(这是销毁内核对象的函数,因此也可以用来销毁信号量及事件)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ML7UXjvN-1641215230601)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103202903380.png)]

获取互斥量是通过WaitForSingleObject函数来实现的

释放互斥量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLWyciMe-1641215230602)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103203024425.png)]

内核状态下的同步------基于信号量的对象同步

和linux下的信号量类似,二者都是利用名为信号量值的整数值完成同步的,而且值都不能小于0

创建信号量对象的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4x1W5lbt-1641215230602)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103203324364.png)]

信号量为0时进入non-signaled状态,大于0进入signaled状态

信号量的释放函数(信号量的获得也是通过WaitforSingleObject()函数获得

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWzvZHdh-1641215230602)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103203449003.png)]

内核状态下的同步基于事件对象的同步

创建事件对象的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-esTLd1gS-1641215230602)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103203714022.png)]

需要通过如下两个函数用来明确更改对象状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-11ng8RkU-1641215230602)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103203905146.png)]

WIndows下的实现多线程服务端以及收发分离的客户端程序

参考《TCP/IP网络编程》P339页

windows提供的扩展I/O模型 理解同步于异步

send&recv函数进行同步I/O。调用send函数时,完成数据传输后才能从函数返回(确切的说,只有把数据完全传输到输出缓冲区后才能返回);而调用recv函数时,只有读到期望大小的数据后才返回。

同步情况下,函数没有返回,就不能进行其他任务,因此异步方式能够比同步方式更加有效的使用CPU

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScArbAKt-1641215230603)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103205038104.png)]

使用WSAEventSelect 函数和通知

它是select函数的异步IO版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W3EDcINi-1641215230603)(C:Users顾子茵AppDataRoamingTyporatypora-user-imagesimage-20220103205344447.png)]

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5694017.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存