Windows网络编程考试要点

Windows网络编程考试知识点汇总

主要为5、8两章

C/S模式

过程

Server

  1. 打开一信道,并告知所在主机,它要在某一公认地址上接收客户请求
  2. 等待客户请求到达该端口
  3. 服务器接收到服务请求,处理该请求并发送应答信号。为了能并发处理多个客户的请求,可创建新的进程或线程处理。服务完成后,关闭通信通路,终止新进程或线程
  4. 返回2,等待并处理另一客户请求
  5. 在特定情况下,关闭服务器进程

Client

  1. 打开一信道,并连接到服务器所在主机的特定监听端口
  2. 向服务器发送请求报文,等待并接收应答,然后继续提出请求。与服务器的会话按照应用协议进行
  3. 请求结束后,关闭信道并终止

特点

  1. C/S都是软件进程
  2. 非对称性
  3. 对等性
  4. 服务器的被动性
  5. 客户机的主动性
  6. 一对多
  7. 分布性和共享性

Socket基本概念

Socket三种类型

  1. 流式套接字(SOCK_STREAM)

    基于TCP。采用的有FTP。

  2. 数据报式套接字(SOCK_DGRAM)

    基于UDP。

  3. 原始套接字(SOCK_RAW)

    公开的Socket编程接口,在IP层编程。

流式套接字和数据报式套接字的区别

比较项目 流式套接字 数据报式套接字
建立和释放连接 T F
保证数据到达 T F
按发送顺序接收数据 T F
通信数据包含完整的目的地址信息 F T

WinSock编程基础

使用Winsock 2.2实现网络通信的应用程序框架

结构体WSADATA用于存储调用WSAStartup()函数后返回的 Windows Socket 数据,它的定义代码如下:

WSAStartup()函数原型:

参数说明:

  • wVersionRequested, 版本信息,高位字节中存储副版本号,低位字节中存储主版本号。
  • lpWSAData, 指针,用与接收Windows Sockets执行的数据。

LOBYTE() 与 HIBYTE() 函数

参数均为WORD类型,LOBYTE获取低位字节,HIBYTE获取高位字节

*大端模式和小端模式

大端模式是指数据的高字节保存在内存的低地址,数据的低地址保存在内存的高地址中

小端模式则相反

NBO和HBO

NBO即网络字节顺序,按从高到低的顺序存储,在网络传输中统一

HBO即主机字节顺序,不同的CPU都不相同,部分采用大端模式,部分采用小端模式

面向连接的Socket编程

通信流程

Server

  1. 建立流式套接字,返回套接字号s // socket()
  2. 套接字s与本地地址(ip+port)绑定 // bind()
  3. 通知TCP,服务器准备好接收连接 // listen()
  4. 等待客户端连接 // accept()阻塞
  5. 建立连接,得到新的套接字,比如ns // accept()返回SOCKET
  6. 在套接字ns上读写数据,直接结束 // send(),recv(),etc
  7. 关闭套接字ns // closesocket()
  8. 关闭最初的套接字s,结束服务 // closesocket()

Client

  1. 建立流式套接字,返回套接字号s // socket()
  2. 将套接字s与远程主机连接 // connect()
  3. 在套接字上读写数据,直接结束 // send(),recv(),etc
  4. 关闭套接字,结束会话 // closesocket()

完整服务端代码

书上代码十分冗余,因为每一步的异常处理都要单独判断,并且处理异常回收资源的代码有大量重复,因此这一块为了应试可以有技巧性的记忆。
– 比如返回值用retVal保存的,判断retVal是不是SOCKET_ERROR,返回值是SOCKET结构体类型的,判断是否INVALID_SOCKET。
– 加载了Socket动态库之后,每一步异常处理都要使用WSACleanup()清理。
– 创建了服务端Socket,但是接受客户端Socket那一步异常时,只需要回收服务端Socket,后面每一步客户端和服务端Socket都要回收。
– return 1或-1并不重要,但是如果按书上代码只有WSAStartup异常return 1,其他异常均return -1。

Socket编程模型

多线程

多线程编程即在一个进程中用多个线程去完成多个任务

使用多线程的目的:
1. 提高吞吐量:C/S模式中,往往多个Client对一个Server发送请求,如果服务端为单线程,则大量请求都将阻塞,采用多线程,可以一请求对应一个线程(早期web开发方案),加快了客户端的响应速度,提高了服务端的吞吐量
2. 提高伸缩性:单线程的程序在单核和多核CPU中运行的性能都是一样的,而多线程程序在多核CPU中运行则能将线程分布到多个处理机上,提高性能

应用场景:

  1. 后台任务(如GUI程序,开多个线程处理后台任务,像本课程中负责socket通信,可以避免GUI界面假死)
  2. 异步处理
  3. 分布式计算

I/O 模型

一个输入操作通常包括两个阶段:
1. 等待数据准备好
2. 从内核向进程复制数据

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待数据到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。

阻塞与非阻塞

  • 阻塞是指在指定Socket上调用函数执行操作时,在没有完成操作之前,函数不会立即返回。
    在阻塞的过程中,其它程序还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其他程序还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率效率会比较高。
  • 非阻塞是指在指定Socket上调用函数执行操作时,无论操作是否完成,函数都会立即返回,程序便可以继续后面的操作。

    应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。

    由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率是比较低的。

Windows平台5种模型

  1. Select模型
  2. WSAAsyncSelect模型
  3. WSAEventSelect模型
  4. 重叠I/O模型
  5. 完成端口模型

设置Socket为非阻塞模式

Select模型

文件描述符集合结构体fd_set代码

select函数

有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义。

timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。

成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。

三种fd_set的就绪条件

  1. readfds
    1. 已调用listen(),后成功建立连接,则调用accept()会成功
    2. 有数据可读
    3. 连接已关闭、重置或中止
  2. writefds
    1. 已经调用非阻塞的connect(),并且连接成功
    2. 有数据可发送
  3. exceptfds
    1. 已经调用非阻塞的connect(),但连接失败
    2. 有带外数据可读取

工作步骤

  1. 定义一个集合fd_set并用fd_zero宏初始化为空
  2. 用FD_SET宏,把套接字句柄加入到fd_set集合
  3. 调用select函数,检查每个套接字的可读可写性,select完成后,会返回所有在fd_set集合中有数据到达的socket的socket句柄总数,并对每个集合进行更新,即没有数据到达的socket在原集合中会被置成空。
  4. 根据select的返回值以及FD_ISSET宏,对FD_SET集合进行检查
  5. 知道了每个集合中“待决”的I/O操作后,对相应I/O操作进行处理,返回步骤1,继续select

select函数返回后,会修改FD_SET的结构,删除不存在待决IO操作的套接字,这也就是为什么我们之后要用FD_ISSET判断是否还在集合中的原因。

WSAAsyncSelect和WSAEventSelect比较

前者为异步选择模型,后者为事件选择模型

相同点:

均会被动选择系统通知应用程序Socket的状态变化

不同点:

主要区别为网络事件发生时系统通知应用程序的方式不同。前者以消息的形式通知应用程序,后者以事件的形式通知。

发表评论

电子邮件地址不会被公开。 必填项已用*标注