经过几日的原理学习和扒码之后,终于七七八八搞明白tcp的通信是怎么进行的了。
注:源码为《C#开源虚拟仪器技术》实例
本文主要给大家提供从零开始做一个包含客户端和服务端的tcp通信窗体应用的教程,并在此基础上理解TCP通信的原理,理解使用socket套接字进行通信的概念和实际运用,全文包含从原理到例程的详细操作,保证简单易上手
TCP的工作过程可分为三个重要的阶段,一是建立连接,二是传输数据,二是断开连接
建立连接最关键的一步就是进行3次握手,这一步主要关注三个“硬性指标”,分别是
详细过程:(同步通信方式)假定服务端向客户端发送信息
注:握手的步骤在协议内部协议实现的,不体现在具体的上位机代码中。理解握手过程即可
建立连接之后,就可以通过通信信道进行传输数据的任务了,但是需要注意的是TCP协议中的数据是以字节流的形式存在的,发送端需要将的数据转换为字节流,然后才可以发送。通常是字符集转换为字节序列,这其中就涉及到编码和解码的问题了。
断开连接主要是关闭读写流。至于是服务端先断开连接还是客户端先断开连接,有时需要进行异常处理。
这一步主要使用工具箱中的按钮button和文本框text控件,点击相应控件即可查看代码。Label控件用于标识文本框。
注意事项:
这里需要注意的是要确保按钮的命名,以及其事件的名称,如客户端的发送按钮,要确保正确。示例如下:
客户端发送按钮
按钮的命名
按钮事件即操作的命名
这一步的命名操作十分关键,关系到实际代码中的运行。以此类推。
为使编程变得简洁,这里使用类库Tcplistener类和TcpClient类实现Tcp通信(已经包含Socket套接字方法),并且服务端server只负责接收信息,客户端只负责发送信息。
如果要实现全双工通信,加入多线程thread,对每个tcp开两个线程,一个线程用来处理发送数据,一个线程用来处理接收数据即可。推荐使用异步通讯方式,无阻塞现象。
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace _13._2._3._1
{
public partial class TCPClient : Form
{
#region 变量
private TcpClient tcpClient = null;
private NetworkStream networkStream = null;
private BinaryWriter writer;
private const int Port = 51388;
private IPAddress ipAddress = IPAddress.Loopback;
private byte[] buffer;
private string messageSend;
#endregion
public TCPClient()
{
InitializeComponent();
textBox_clientIP.Text = ipAddress.ToString();
textBox_port.Text = Port.ToString();
}
private void button_connect_Click(object sender, EventArgs e)
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(textBox_clientIP.Text, int.Parse(textBox_port.Text));
if (tcpClient != null)
{
MessageBox.Show("连接成功");
networkStream = tcpClient.GetStream();
writer = new BinaryWriter(networkStream);
}
}
catch(Exception ex)
{
MessageBox.Show("连接失败,请重试" + ex.Message);
}
}
// 发送消息
private void btnSend_Click(object sender, EventArgs e)
{
messageSend = textBox_messageSend.Text;
if (messageSend != string.Empty)
{
writer.Write(messageSend);
Thread.Sleep(500);
writer.Flush();
}
textBox_messageSend.Clear();
}
// 断开连接
private void btnDisconnect_Click(object sender, EventArgs e)
{
writer?.Close();
tcpClient?.Close();
}
}
}
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _13._2._3._2
{
public partial class TCPServer : Form
{
private const int Port = 51388;
private TcpListener tcpLister = null;//创建对象,对象和类的属性以及行为完全相同
private TcpClient tcpClient = null;
IPAddress ipAddress = IPAddress.Loopback;//将IPAddress类中的属性Loopback赋给对象ipAddress,即127.0.0.1
private NetworkStream networkStream = null;
private BinaryReader reader;
private byte[] buffer = new byte[1024];
private string messageReceived;
public TCPServer()
{
InitializeComponent();
textBox_serverIP.Text = ipAddress.ToString();//当前对象以字符串形式返回
textBox_port.Text = Port.ToString();
}
// 开始监听
private void btnStart_Click(object sender, EventArgs e)
{
try
{
tcpLister = new TcpListener(IPAddress.Parse(textBox_serverIP.Text),
int.Parse(textBox_port.Text));
tcpLister.Start();
tcpClient = tcpLister.AcceptTcpClient();
if (tcpClient != null)
{
networkStream = tcpClient.GetStream(); //获取网络流对象
reader = new BinaryReader(networkStream); //从网络流中初始化读取对象
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void button_receive_Click(object sender, EventArgs e)
{
messageReceived = reader.ReadString();
listBox_messageReceived.Items.Add(messageReceived);
}
private void btnStop_Click(object sender, EventArgs e)
{
tcpLister?.Stop();
}
private void button_disconnect_Click(object sender, EventArgs e)
{
reader?.Close();//断开连接,关闭读写流
tcpClient?.Close();
}
}
}
注:源码为《C#开源虚拟仪器技术》实例
参考资料链接:
《C#开源虚拟仪器技术》
https://blog.csdn.net/weixin_46594796/article/details/107881821
https://javaedge.blog.csdn.net/article/details/113784188
https://blog.csdn.net/qq_45060045/article/details/113360983
https://blog.csdn.net/weixin_38247439/article/details/88529909
https://blog.csdn.net/kevinfan2011/article/details/84660013