TCP/IP五层模型消息解/封装仿真
来源:互联网 发布:matlab cell数组 拼接 编辑:程序博客网 时间:2024/06/04 18:44
来自我的博客Minecode.link
消息封/解装仿真
功能要求
按照TCP五层模型仿真消息在两台主机之间的通信过程。
1. 在发送端模拟数据从高层到低层的封装过程,在接收端模拟数据从低层到高层的解封装过程。
2. 按照每层的功能对数据填加报头,并显示每一层得到的封/解装格式。
3. 传输层和网络层的封装格式参考TCP/IP的相应各层协议格式。
4. 网络层的IP报文需要模拟报文分段和重组的过程。
5. 数据链路层帧格式参考局域网的MAC帧格式。
6. 物理层显示为0或1比特串。
Socket编程简介
Socket是网络文件描述符。在基于Socket的编程技术中,用户不直接访问发送和接收包的网络接口设备,而是建立一个中间文件描述符来处理编程接口到网络的操作。简单来说,Socket就是我们常说的“套接字”。
本段只介绍了本实验需要设计的知识,更多Socket用法可Google一下。
Socket包含的内容
- 一个特殊的通信域,比如一个网络连接
- 一个特殊的通信类型,比如流或者数据报
- 一个特殊的协议,比如TCP或者UDP
其中,可以实现面向连接和无连接的Socket
面向连接的Socket
面向无连接的Socket
模拟TCP
最终效果
运行逻辑
本实验模拟了TCP五层模型中的消息解/封装仿真,建立在现有网络的基础上,使用Socket进行通信,使用了面向连接的Socket。除了两台机器相互通信之外,我们也可以将服务端绑定到网卡端口,使用客户端与服务端在本机相互通信。
由服务端绑定端口并侦听客户端消息。而后客户端连接服务端,并相互发送消息。
服务端(Server)
首先,服务器绑定端口,并侦听客户端连接请求,当客户端连接后进行消息侦听和发送。
- (void)bindSocketWithPort:(NSInteger)port { // 创建Socket地址 struct sockaddr_in server_addr; // socket地址 server_addr.sin_len = sizeof(struct sockaddr_in); // 设置地址结构体大小 server_addr.sin_family = AF_INET; // AF_INET地址簇 server_addr.sin_port = htons((short)port); // 设置端口 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务器地址 // 创建Socket int server_socket = socket(AF_INET, SOCK_STREAM, 0); // 创建Socket if (server_socket == -1) { [self showMessageWithMsg:@"创建Socket失败"]; return; } int reuse = 1; int sockOpt = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (sockOpt == -1) { [self showMessageWithMsg:@"重设Socket失败"]; return; } // 绑定Socket // 将创建的Socket绑定到本地IP和端口,用于侦听客户端请求 int bind_result = bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (bind_result == -1) { [self showMessageWithMsg:@"绑定Socket失败"]; return; } // 侦听客户端消息 if (listen(server_socket, 5) == -1) { [self showMessageWithMsg:@"开启侦听失败"]; return; } // 获取客户端端口信息 struct sockaddr_in client_address; socklen_t address_len; int client_socket = accept(server_socket, (struct sockaddr *)&client_address, &address_len); if (client_socket == -1) { [self showMessageWithMsg:@"客户端握手失败"]; return; } char recv_msg[RECV_BUFFER_SIZE]; char reply_msg[REPLY_BUFFER_SIZE]; while (YES) { bzero(recv_msg, RECV_BUFFER_SIZE); bzero(reply_msg, REPLY_BUFFER_SIZE); long byteLen = recv(client_socket, recv_msg, RECV_BUFFER_SIZE, 0); recv_msg[byteLen] = '\0'; // 添加消息结尾 NSMutableString *msgStr = [NSMutableString stringWithFormat:@"%s", recv_msg]; [self clearCurrentMsg]; strcpy(recv_msg, [[self reciveFromClient:msgStr] UTF8String]); if (strcmp(recv_msg, "") != 0) { strcpy(reply_msg, "服务端消息:收到"); strcat(reply_msg, recv_msg); send(client_socket, reply_msg, REPLY_BUFFER_SIZE, 0); } }}
客户端(Client)
首先,客户端要和服务端建立连接。调用socket的方法顺序为:
socket() -> connect()
- (void)bindSocketWithIP:(NSString *)ipStr andPort:(NSInteger)port { // 创建Socket地址 struct sockaddr_in server_addr; // 创建Socket地址 server_addr.sin_len = sizeof(struct sockaddr_in); // 设置结构体长度 server_addr.sin_family = AF_INET; // AF_INET地址簇 server_addr.sin_port = htons((short)port); // 设置端口 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务器地址 // 创建Socket int server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { [self showMessageWithMsg:@"创建Socket失败"]; return; } else { // 保存Socket self.server_socket = server_socket; // 保存port self.port_num = (short)port; [self showMessageWithMsg:@"创建Socket成功"]; [NSThread sleepForTimeInterval:0.3]; } int connect_result = connect(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)); if (connect_result == -1) { [self showMessageWithMsg:@"连接主机失败"]; return; } else { [self showMessageWithMsg:@"连接主机成功,等待发送消息..."]; [NSThread sleepForTimeInterval:0.3]; } // 连接成功后的操作 [self didConnected];}
连接成功后,双方互相发送和接收消息
send() -> recv()
- (void)sendMsgAction { NSMutableString *msg = [NSMutableString stringWithFormat:@"%@",self.msgField.stringValue]; char recv_msg[RECV_BUFFER_SIZE]; char send_msg[REPLY_BUFFER_SIZE]; // 发送消息,并接收服务器回信 bzero(recv_msg, RECV_BUFFER_SIZE); bzero(send_msg, REPLY_BUFFER_SIZE); // 向服务端通过socket发消息 NSMutableString *resStr = [self appLayerWithString:msg]; strcpy(send_msg, resStr.UTF8String); long send_result = send(self.server_socket, send_msg, REPLY_BUFFER_SIZE, 0); if (send_result == -1) { [self showMessageWithMsg:@"消息发送失败"]; return; } else { [self showMessageWithMsg:@"消息发送成功"]; [NSThread sleepForTimeInterval:0.3]; } // 接收服务端消息 long recv_result = recv(self.server_socket, recv_msg, RECV_BUFFER_SIZE, 0); [self reciveFromServer:[NSString stringWithUTF8String:recv_msg]];}
报头编码
各层在传递给下一层之前,要对数据进行封装,增加对应的报头。具体代码如下:
#pragma mark - 五层传输协议// 模拟网络层对数据的包装- (NSMutableString *)appLayerWithString:(NSMutableString *)str { NSMutableString *resStr = [NSMutableString stringWithFormat:@"AppHeader#%@", str]; dispatch_async(dispatch_get_main_queue(), ^{ self.appLayer.stringValue = [resStr copy]; }); [NSThread sleepForTimeInterval:0.3]; return [self transferLayerWithString:resStr];}// 模拟传输层对数据的包装- (NSMutableString *)transferLayerWithString:(NSMutableString *)str { NSMutableString *resStr = [NSMutableString string]; // 添加源端口 16位(0-15) [resStr appendFormat:@"0000000011111111"]; // 添加目的端口 16位(16-31) [resStr appendFormat:@"%@", [self intToBinary:self.port_num]]; // 添加序列编号 32位 [resStr appendFormat:@"00000000000000000000000000001011"]; // 添加确认帧 32位 [resStr appendFormat:@"00000000000000000000000011111011"]; // 添加报头长度 [resStr appendFormat:@"0101"]; // 添加保留长度 [resStr appendFormat:@"000000"]; // 添加FLag [resStr appendFormat:@"000000"]; // 添加窗口大小 [resStr appendFormat:@"0000000000000111"]; // 添加确认值 [resStr appendFormat:@"0101010101010010"]; // 添加UrgentPointer [resStr appendFormat:@"0000000000001111"]; // 添加Header结尾 [resStr appendFormat:@"#%@", str]; dispatch_async(dispatch_get_main_queue(), ^{ self.transLayer.stringValue = [resStr copy]; }); [NSThread sleepForTimeInterval:0.3]; return [self networkLayerWith:resStr];}// 模拟网络层对数据的包装- (NSMutableString *)networkLayerWith:(NSMutableString *)str { NSMutableString *resStr = [NSMutableString string]; // 添加VER [resStr appendFormat:@"0100"]; // 添加HLEN [resStr appendFormat:@"1111"]; // 添加Service [resStr appendFormat:@"00000000"]; // 添加totalLength [resStr appendFormat:@"0101010101010101"]; // 添加Identification [resStr appendFormat:@"0000000000000000"]; // 添加Flag [resStr appendFormat:@"000"]; // 添加FragmentationOffset [resStr appendFormat:@"0000000000000"]; // 添加TTL [resStr appendFormat:@"00000000"]; // 添加Protocol [resStr appendFormat:@"00000000"]; // 添加HeaderChecksum [resStr appendFormat:@"0000000000000000"]; // 添加SourIPAddress [resStr appendFormat:@"00000000000000000000000000000000"]; // 添加DestinationIPAddress [resStr appendFormat:@"00000000000000000000000000000000"]; // 添加Header结尾 [resStr appendFormat:@"#%@", str]; dispatch_async(dispatch_get_main_queue(), ^{ self.networkLayer.stringValue = [resStr copy]; }); [NSThread sleepForTimeInterval:0.3]; return [self dlinkLayerWithString:resStr];}// 模拟链路层对数据的包装- (NSMutableString *)dlinkLayerWithString:(NSMutableString *)str { NSMutableString *resStr1 = [NSMutableString string]; // 添加FrameFlag1 [resStr1 appendFormat:@"00001111"]; // 添加FrameAdd [resStr1 appendFormat:@"11101011"]; // 添加FrameControl [resStr1 appendFormat:@"01111000"]; NSMutableString *resStr2 = [NSMutableString string]; // 添加FrameFCS [resStr2 appendFormat:@"00001111"]; // 添加FrameFlag2 [resStr2 appendFormat:@"11101011"]; // 合成帧 NSMutableString *resStr = [NSMutableString stringWithFormat:@"%@#%@#%@", resStr1, str, resStr2]; dispatch_async(dispatch_get_main_queue(), ^{ self.dlinkLayer.stringValue = [resStr copy]; }); [NSThread sleepForTimeInterval:0.3]; return [self phyLayerWithString:resStr];}// 模拟物理层对数据的包装- (NSMutableString *)phyLayerWithString:(NSMutableString *)str { NSMutableString *resStr = [NSMutableString stringWithFormat:@"PhysicsHeader#%@", str]; dispatch_async(dispatch_get_main_queue(), ^{ self.phyLayer.stringValue = [resStr copy]; }); [NSThread sleepForTimeInterval:0.3]; return resStr;}
其他细节
1、在定义Socket地址端口时,要注意端口值类型,若使用htons,则需要转换为short类型(16位)。 server_addr.sin_port = htons((short)port);
本文源代码:Github: https://github.com/Minecodecraft/TCP-IP-Model-Simulation
原文地址:Minecode’s Blog: TCP五层模型消息解/封装仿真
- TCP/IP五层模型消息解/封装仿真
- TCP/IP协议五层模型浅析
- tcp/ip五层网络模型
- TCP/IP五层模型的协议
- TCP/IP五层模型的协议
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型 vs TCP/IP五层模型
- OSI七层模型 和 TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- OSI七层模型和TCP/IP五层模型
- OSI七层模型与TCP/IP五层模型
- 成为Android高级工程师看这里就够了
- 随手记-处理图片内存溢出
- vue 刷新当前路由
- [LeetCode] [C++] 62. Unique Paths
- ActiveMQ之集群(主从)搭建-yellowcong
- TCP/IP五层模型消息解/封装仿真
- 营养餐 阶梯博弈
- Dagger2的简单使用
- springMVC中两种validation的简单使用
- 如何支付宝微信购买比特币?
- 处理excel
- Linux安装Java jdk
- PHP安全总结
- 像素与dp相互转换