WSAStartup 成功之后应该是将 wsaData 的结构体中的字段进行赋值了,因为传入的是它的指针。

WSAStartup 应该是进行准备 socket 环境的工作

SOCKET socket (int af, int type, int protocol); 中 af 的地址簇是什么意思

ipv4 等

https://blog.csdn.net/m0_38062470/article/details/110680118

https://blog.csdn.net/linglongbayinhe/article/details/83214171

https://blog.csdn.net/jeffasd/article/details/51461568

在 listen 的 backlog 的描述中,服务器是不支持并发的么

listen 因为 backlog 而不能连接的时候,算是执行失败么

在 accept 函数的第二个参数 addr 开始指向的是空结构体,连接成功才会将结构体的字段赋值

connect 的第一个参数 s 是发送连接请求的,还是接收连接请求的

为什么设计到目标地址结构体时要加上结构体的长度呢?

typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
typedef UINT_PTR        SOCKET;

https://blog.csdn.net/Fuel_Ming/article/details/122931926

文件描述符

https://zhuanlan.zhihu.com/p/143847169

https://baike.baidu.com/item/ 文件描述符 / 9809582

https://blog.csdn.net/yuhan61659/article/details/81746043

将 socket 设置非阻塞模式的时机,在创建 socket 的时候它有默认的模式么?

默认是阻塞模式

socket 就是文件描述符(SOCKET),

参考作品:https://github.com/UncleBloom/httpServer

文件描述符应该是标识一个文件缓冲区,

select 的作用是什么?

是怎么监听到客户端发来信息的?

在哪里检测到客户端来连接的

如果 select 用来检测文件描述符指向的文件是否发生变化的话,那么为什么在客户端没有连接的时候,select 是阻塞的,客户端连接之后,就不阻塞了

上面的发生变化是指只要客户端连接进行,还是需要客户端发送来消息呢?

select 的参数中

int maxfdp 是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加 1,不能错!在 Windows 中这个参数值无所谓,可以设置不正确。

若将 NULL 以形参传入,即不传入时间结构,就是将 select 置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止

select 设置的 write 和 read 之间会发生通信、数据传递么?

select 的作用是通过文件标识符来监视文件的变化的,write 和 read 是不同的文件类型,可能设置监视的方式不同,因此要分开,这和它们的通信、数据传递无关。

“每次循环都要清空,否则不能检测描述符变化” 这是为什么?

如果在 select 的地方阻塞了,那么,客户端发送请求的时候,又该怎么运行代码来改变文件标识符指向的文件呢?

是 listen 起的作用还是 bind 起的作用,listen 起的作用,bind 是将 socket 和地址进行了绑定,listen 是开启监听,之后才能接受请求。

应该是,当 select 的返回值是 0 的时候,就会发生阻塞

有了 FD_SET(srvSocket, &rfds); ,那么当 srvSocket 接受到请求的时候,它就会发生变化。

ioctlsocket(srvSocket, FIONBIO, &blockMode) 将 socket 设置为非阻塞模式是在哪个地方起作用的呢?

https://blog.csdn.net/yuhan61659/article/details/81746043

select 是会修改传入的 fd_set 的 read 和 write 指针的,根据

这里面

的解释,应该是清除不满足条件的了,

那如何判断是否满足条件呢?sessionSocket 始终不满足读的条件,srvSocket 在接受了请求之后就不再满足读的条件了。

百度百科

select 的选择性: https://blog.csdn.net/xhu_eternalcc/article/details/24439453

但是,select 判断文件描述符指向的文件是否有事件发生,这个事件得在什么时候发生才能被 select 选中呢?

依据刚建立连接时候的情形,select 应该是阻塞的,一直在等待连接,

那是否是,select 只能选择一个呢?即只要有一个发生变化了,select 就会返回了。

select 可以设置阻塞,也可以设置非阻塞,在这里由于最后一个参数设置为 null,所以是阻塞的。

当已经建立连接,但是客户端没有发送消息,为什么 sessionSocket 能够一直留在 wfds 中呢?

难道是因为,可写的就是会一直存留

新创建一个 SOCKET,然后加入试试。貌似是对的,当在 select 前 sessionSocket = 2; FD_SET(sessionSocket, &wfds); 时,这时没有开启客户端,select 就不再阻塞了。随便设置的会出现 ioctlsocket() failed with error! 的错误。

struct sockaddr_in {
	short sin_family;
	u_short sin_port;
	struct in_addr sin_addr;
	char sin_zero[8];
};
struct in_addr {
	union {
		struct { u_char s_b1, s_b2, s_b3, s_b4; } S_un_b;
		struct { u_short s_w1, s_w2; } S_un_w;
		u_long S_addr;
	} S_un;
};

代码跑起来了,现在去根据他的代码内部的数据处理,得到正确的输入输出,

输入的都是字符串,思考代码内部的转换过程。

当前代码好像还没有 WSAStartup

输入的 ip 地址为点分十进制,

我们输入的 ip 应该是本机的 ip 吧,不能是任选的;

127.0.0.1

在 main 函数中配置服务器的时候就配置 filepath 了么?
这不是请求的文件,而是文件夹的路径。

http://127.0.0.1:5050

ip.src ==127.0.0.1 && tcp.port == 5050

ip.addr ==127.0.0.1

目前的问题,在重新配置网络之后,浏览器发出的网络请求仍然是针对旧端口和 ip 的,

看 main 函数捋清楚执行过程查找使用当前服务器使用的 ip 和端口号,在重新读取文件后重置他们的值

# 模块二

RdtReceiver 中的 receive (Packet) 要进行数据的检验

# 实验二

“编码报文序号的二进制位数” 是什么,

超时 TimeoutHandler 是由网络环境调用的么

计时器是放在网络环境中的,因此也是网络环境调用 TimeoutHandler

1669549188840

上面是不是错误了,当传输了多个数分组了,每当一个分组传输成功后不是重启定时器的么

StopWait、GBN、简化版的 TCP 协议只需要一个定时器

在 Packet 中的序号和确认号

是和该定时器相关的 Packet 序号 是什么意思

即使是 GBN 和简化版 TCP 这些协议,也要设置该参数(应为最早发出但未确认的 Packet 序号)

根据上面这句话,Packet 的序号是否是连续的

先配置环境,主要是 stdafx.h 中的库路径

在头文件中 GBNReceiver.h 、 GBNSender.h、SRReceiver.h、SRSender.h、TCPReceiver.h、TCPSender.h。

响应的,有 GBNReceiver.cpp 、 GBNSender.cpp 、 SRReceiver.cpp 、 SRSender.cpp 、 TCPReceiver.cpp 、 TCPSender.cpp

序号和确认号是怎么发挥作用的

# GBN

expectSequenceNumberSend 为当前使用的序号,同时对应 packetWaitingAck 数组中的下标

在一开始的时候 expectSequenceNumberRcvd 怎么设置,如果发送方是从 0 开始发送的话,那么 expectSequenceNumberRcvd 应该设置为 0

这里有重发分组,如果是第一个分组就出错了呢?

报文和分组有区别的么

# GBNSender

发送方接收到一个 ack 分组之后就关闭定时器,如果还存在已发送但没接受到 ack 的分组,就重启定时器。

# GBNReceiver

在 GBNReceiver 中,

在 GBNReceiver 中仅设置了一个 lastAckPkt 来保存上次发送确认的报文?

由 GBNReceiver 发送的分组 Packet 没有用到 seqnum 字段,只用到了 acknum 字段,且 acknum 等于正确接受到的分组的 seqnum

expectSequenceNumberRcvd 是递增的,意味着只能按顺序接受分组,没有按序接受时,则发送上次确认的分组

# SR

# SRSender

窗口长度为 N=4

expectSequenceNumberSend

sureNum 和 packetWaitingAck 的数组长度是一致的,且主要用 expectSequenceNumberSend 索引

sureNum 在某序号处为 0 时,表示该分组已分送但未确认,发送且确认则置为 1

# SRReceiver

窗口长度为 M=4

loadPkt 用来缓存的报文 ? 它的长度设置为 8 ?如果考虑窗口的大小为 4,那长度为 4 是不是就行了?

在 loadPkt 的确认号 acknum 也等于接收到的分组的序号 seqnum

无论是窗口内的还是窗口外的分组被接收后都要给出回复的 ACK,这个 ack 就是接受到的分组的序列号

rcv_base 是缓存数组中窗口的开始下标,但是它指向的分组不一定是已被缓存的,即 acknum=-1

# TCP

快速重传:https://blog.csdn.net/whgtheone/article/details/80983882

加入发送方收到

# TCPReceiver

发送的 ack 分组的 ack 序号就是接受的分组的 seqnum 序号

发送方的 base 和接收方的 rcv_base 是相同的么?
某一时刻不相同,但目的是为了使相同。
是的,当序号较大分组首先到达接收方时,rcv_base 是不更新的。当接受方窗口内的分组从窗口开始位置有连续到达时,rcv_base 更新,发送的 ack 传到发送方,使它的 base 更新到和 rcv_base 相同。

# 实验三

PDU: https://blog.csdn.net/qq_39806533/article/details/81877588

https://blog.csdn.net/weixin_39856589/article/details/110993720#:~:text = 不同的网段之间的,好多人想不到:)

交换机,路由器上的 S 口 F 口 E 口 G 口 是什么? https://blog.csdn.net/immenselee/article/details/80401059

子网划分

每个 200,8 位
宿舍 1: 211.69.4.0/24
宿舍 2: 211.69.5.0/24
宿舍 3: 211.69.6.0/24

每个 20,5 位
学院 1: 211.69.7.128/27
学院 2: 211.69.7.160/27
学院 3: 211.69.7.192/27
学院 4: 211.69.7.224/27

图书馆 100 7 位
211.69.7.0/25