- 网线制作
原始线序:(顺序记忆方法:红橙黄绿青蓝棕)
| 白橙 | 橙 | 白绿 | 绿 | 白蓝 | 蓝 | 白棕 | 棕 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
568B:原始线序第4个与第6个交换
| 白橙 | 橙 | 白绿 | 蓝 | 白蓝 | 绿 | 白棕 | 棕 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
568A:568B线序第1个与第3个交换,第2个与第6个交换
| 白绿 | 绿 | 白橙 | 蓝 | 白蓝 | 橙 | 白棕 | 棕 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
注意事项:水晶头的塑料卡一面向下,从左到右依次按1-8的顺序排列线。
2.网络编程
- TCP协议
客户-服务器模式
| Client | Server |
|
| =socket() | socketid=socket() |
|
| =connect() | =bind() | 分配资源 |
|
| =listen(socketid,queuelen) |
|
|
| =accept() | 同意建立连接,发送ack,反向连接请求,返回newsocket,建立新的套接字数据结构 三次握手 |
| =send() | =recv() |
|
| =recv() | =send() |
|
| =close() | =close(socketid) | 四次挥手 |
|
| =close(newsocket) |
|
- Client通过connect函数写入Server的IP地址和端口号
- Server的accept函数返回Client的IP地址和端口号(指针)
- Server通过bind函数绑定自己的IP地址和端口,周知端口号
- Client不需要bind函数,因为操作系统临时分片端口;也可以绑定,此时操作系统不分配
- Server可以向Client主动发送数据,因为三次握手后Server获得了Client的地址
- UDP协议
| Client | Server |
|
| =socket() | socketid=socket() |
|
|
| =bind() | 分配资源 |
| =sendto() | =recvfrom() |
|
| =recvfrom() | =sendto() |
|
| =close() | =close(socketid) |
|
- Client的sendto指明Server的IP地址和端口号
- Server的recvfrom指明Client的IP地址和端口号(指针)
- Server不可以主动向Client发送数据,因为必须接收一次才可以获得Client的地址
思考问题:为什么不在数据链路层和网络层解决可靠性问题?
1交换机和路由器要进行 流量控制、差错控制、拥塞控制,会更复杂
2不仅要在端节点解决可靠性,还要在网络中解决可靠性,网络会复杂
实验方法及具体步骤
TCP协议发送一个大文件姚静.avi
服务器端截图:


可以看到打印出了文件的长度为3838464(字节),我们使用的TCP包的大小是512(字节),所以发送次数=3838464/512=7497次;
TCP服务器端代码:
#define packet_size 512//包长度512
char *sendData = (char*)malloc(length);
char *dataptr = sendData;
ret = sendto(newSocket, dataptr, packet_size, 0, (sockaddr *)&clientAddr, iLen);//发送第一个包
int i = 1;
int send_no = (length / packet_size);//控制发送次数
while ( i < send_no)
{
dataptr += packet_size;//指针移动512
Sleep(5);
if (ret == SOCKET_ERROR || ret == 0)
{
cout << ret << endl;
cout << "wrong" << endl;
return;
}
cout << i << "send successful!" << endl;
if (i < length / packet_size) {
ret = sendto(newSocket, dataptr, packet_size, 0, (sockaddr *)&clientAddr, iLen);//发送前面部分的数据
}
else {
cout << "最后一段数据" << (length % packet_size) << endl;
ret = sendto(newSocket, dataptr, length%packet_size,0,(sockaddr*)&clientAddr, iLen);//发送最后一段数据,这一段数据是文件长度%包长度
}
i++;
}
客户端截图:

UDP协议传送一个小文件zhuqi.txt
服务器端截屏:

可以看到打印出了文件长度为57,只需要发送一次就行了。
客户端截图:

UDP协议传送一个大文件姚静.avi
服务器端截图:


可以看到文件长度为3838464(字节),本次使用的UDP包的大小为53000(字节),所以发送次数=3838464/53000+1=73
部分代码解释:
#define packet_size 53000
char *sendData = (char*)malloc(length);//发送数据的字符数组
char *dataptr = sendData;//新建一个指针指向字符数组的头
ret = sendto(sSocket, dataptr, packet_size, 0, (sockaddr *)&cliadd, ilen);//发送第一个包
int i = 1;
int send_no = (length / packet_size);//发送次数=文件长度/包长度
while (i==send_no||i<send_no)
{
dataptr += packet_size;//字符数组指针后移53000,这样子可以做到下次从53000字节后面开始发送
Sleep(50);
if (ret == SOCKET_ERROR || ret == 0)
{
cout << ret << endl;
cout << "wrong" << endl;
return ;
}
cout <<i<< "send successful!" << endl;
if (i < length/packet_size) {
ret = sendto(sSocket, dataptr, packet_size, 0, (sockaddr *)&cliadd, ilen);//如果发的数据不是最后一段
}
else {
cout << "最后一段数据" << (length % packet_size) << endl;
ret = sendto(sSocket, dataptr,length%packet_size , 0, (sockaddr *)&cliadd, ilen);
//发送最后一段。单独写是因为最后一段有可能不满53000,需要发送的长度是文件长度%包长度
}
i++;
}
遇到的问题:
- UDP的sendto函数有最大长度的限制,我发现这个大小接近53000,如果超过了,sendto函数会返回-1。
解决方法:分包发送
(2)TCP的recv函数可以接收两个send,甚至多个,他们之间不是像udp那样一一对应的,导致代码从udp移植到tcp的时候出现了问题。
解决方法:搜索到tcp也可以使用recvfrom和sendto函数,并且我让所有的sendto都发送同样的大小的包。
参考文献
UDP传输数据及文件
https://blog.csdn.net/ni9htmar3/article/details/53556279
Linux下Socket网络编程send和recv使用注意事项
本文详细介绍了计算机网络实验中TCP和UDP协议的使用。在TCP实验中,发送了一个大文件,通过TCP连接分多次发送。而在UDP实验中,发送了小文件和大文件,展示了UDP的一次性发送和分包发送。实验揭示了TCP和UDP在可靠性、流量控制上的差异,并记录了解决编程中遇到的问题和方法。
3927

被折叠的 条评论
为什么被折叠?



