上位机如何与单片机通信_上位机面试必备——TCP通信灵魂二十问【上】

bb47fdaf7e33827ff6c020d1c3333ae9.png

TCP通信协议应该是上位机开发中应用最广泛的协议,无论是西门子S7协议、三菱MC协议或者是欧姆龙的Fins-TCP协议等,都是TCP通信协议的典型应用。很多人在上位机面试时,都会被问到关于TCP通信的一些问题,比如三次握手和四次挥手、TCP与Socket之间的联系等,为了便于大家更好地理解TCP通信,我整理了一套关于TCP通信的20个常见的面试题:

01OSI参考模型与TCP/IP参考模型的区别?

ab5342d54261b11a1fb1a07f81434a5d.png
OSI参考模型与TCP/IP参考模型

如上图所示,OSI参考模型为7层模型,依次为应用层、表示层、会话层、传输层、网络层、数据链路层及物理层,TCP/IP模型是在OSI参考模型的基础上做了一定的精简,形成一个4层模型。在层次关系上,两者都采用了分层体系结构,都是对等的层间通信,不同之处在于TCP/IP参考模型比OSI参考模型层次更清晰简练,在功能上,两者差别不大,都是为了实现两个或多个终端之间的通信。

02TCP通信位于网络模型的哪一层?

TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,无论是OSI参考模型,还是TCP/IP参考模型,TCP都位于传输层,TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。

03:如何理解面向连接、可靠、字节流?

面向连接:意味着TCP是点对点之间的通信,不能像UDP那样可以一个主机同时向多个主机发送消息,也就是无法实现一对多的情形。

可靠的:无论网络链路如何变化,TCP都可以保障报文能够到达接收端。

字节流:基于字节流,意味着无论我们消息有多大都可以进行传输。并且消息是有序的,当前一个消息没有收到的时候,即使它先收到了后面的字节已经收到,那么也不能扔给应用层去处理,同时对重复的报文会自动丢弃。

04:为什么需要TCP协议?

因为IP层是不可靠的,它不保证网络包的一定交付、不保证按序交付、也不保证完整交付。因此如果需要保证网络数据包的可靠性,就必须要通过上层即传输层的TCP协议来保证。

05:TCP与UDP之间区别及联系?

TCP与UDP都属于传输层协议,区别如下:

  • 连接机制

TCP 是面向连接的传输层协议

UDP 是不需要连接

  • 服务对象

TCP 是一对一的两点服务

UDP 支持一对一、一对多、多对多

  • 可靠性

TCP 保证数据不丢失、不重复、按需到达

UDP 是尽最大努力交付,不保证交付数据

  • 拥塞控制、流量控制

TCP 有拥塞控制和流量控制机制

UDP 则没有拥塞控制和流量控制机制

06:TCP首部报文分析

TCP的首部至少占用20个字节,包含的内容有源端口号、目标端口号、序列号、应答号、控制位、校验和等,具体如下所示:

d18739ac4728fa784eaef742ec0d1850.png

07:简要说明TCP三次握手

83c85bb099d49703924df3309fe9c366.png
  • 服务器与客户端均处于CLOSE状态
  • 服务器先主动监听某端口,处理LISTEN状态
  • 客户端发送SYN报文,seq=x,SYN=1
  • 服务器回复SYN+ACK报文,seq=y,ack=x+1,SYN=1,ACK=1
  • 客户端回复ACK报文,ack=y+1,ACK=1

08:简要说明TCP四次挥手

0f29db6f42542c3127b1a1164d7c4d59.png
  • 服务器与客户端均处于ESTABLISHED状态
  • 客户端打算关闭连接,发送一个 FIN 报文,进入 FIN_WAIT_1 状态。
  • 服务端回复 ACK报文,进入 CLOSED_WAIT 状态。
  • 客户端收到 ACK 应答报文后,进入 FIN_WAIT_2 状态。
  • 服务端处理完数据后,向客户端发送 FIN 报文,进入 LAST_ACK 状态。
  • 客户端回复一个 ACK 应答报文,之后进入 TIME_WAIT 状态
  • 服务器收到 ACK 应答报文后,进入了 CLOSE 状态,服务端完成连接的关闭。
  • 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,客户端也完成连接的关闭。

09:TCP握手为什么刚好是三次?

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用「两次握手」和「四次握手」的原因:

两次握手:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;

四次握手:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

10:TCP挥手为什么需要四次?

回顾下四次挥手双方发 FIN 包的过程,就能理解为什么挥手需要四次:

  • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
  • 由于服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C#上位机单片机之间进行TCP通信数据传输,需要编写两端的代码。下面是一个简单的示例代码,演示了如何在C#上位机和STM32单片机之间进行TCP通信数据传输。 C#上位机代码: ```c# using System; using System.Net; using System.Net.Sockets; using System.Text; public class TcpClientExample { public static void Main() { try { // 创建一个新的TcpClient对象 TcpClient tcpClient = new TcpClient(); // 连接到STM32单片机的IP地址和端口号 tcpClient.Connect(IPAddress.Parse("192.168.1.100"), 1234); // 获取网络流对象 NetworkStream networkStream = tcpClient.GetStream(); // 发送数据到STM32单片机 byte[] sendBytes = Encoding.UTF8.GetBytes("Hello STM32!"); networkStream.Write(sendBytes, 0, sendBytes.Length); // 接收STM32单片机的回复 byte[] receiveBytes = new byte[1024]; int receiveCount = networkStream.Read(receiveBytes, 0, receiveBytes.Length); string receiveString = Encoding.UTF8.GetString(receiveBytes, 0, receiveCount); Console.WriteLine("Received from STM32: {0}", receiveString); // 关闭网络流和TcpClient对象 networkStream.Close(); tcpClient.Close(); } catch (Exception ex) { Console.WriteLine("Exception: {0}", ex); } } } ``` STM32单片机代码(使用ST的HAL库): ```c #include "stm32f4xx_hal.h" #include <string.h> #define TCP_SERVER_PORT 1234 void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART6_UART_Init(void); static void MX_ETH_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART6_UART_Init(); MX_ETH_Init(); // 创建一个TCP服务器 int serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverSocket < 0) { Error_Handler(); } // 绑定服务器IP地址和端口号 struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_port = htons(TCP_SERVER_PORT); if (bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { Error_Handler(); } // 监听客户端连接请求 if (listen(serverSocket, 1) < 0) { Error_Handler(); } while (1) { // 接受客户端连接请求 struct sockaddr_in clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); int clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &clientAddrLen); if (clientSocket < 0) { Error_Handler(); } // 接收客户端发送的数据 char buf[1024]; int rcvCnt = recv(clientSocket, buf, sizeof(buf), 0); if (rcvCnt > 0) { printf("Received from C#: %s\n", buf); // 发送回复给客户端 char *sendStr = "Hello C#!"; int sendCnt = send(clientSocket, sendStr, strlen(sendStr), 0); if (sendCnt < 0) { Error_Handler(); } } // 关闭客户端连接 close(clientSocket); } } ``` 注意:以上代码仅供参考,实际使用时需要根据自己的需求进行修改。在实际应用中,还需要考虑网络传输的稳定性和安全性等题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值