下面修改一下上一节的服务器端,使得可以连续接收客户端发过来的消息,另外要开启多线程
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
Thread acceptThread = new Thread(() =>
{
IPAddress ip = IPAddress.Parse(this.textBoxIP.Text);//创建IP
listener = new TcpListener(ip, Convert.ToInt32(this.textBoxPort.Text));//创建TCP监听对象
listener.Start();
this.textBoxInfo.Text = "服务器启动-" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
tcpClient = listener.AcceptTcpClient();//中断 等待
this.textBoxInfo.Text = "连接成功-" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);//会把流里面的字节数组 放到byteArray里面
//length其实就是客户端发送的字节数组长度
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
this.textBoxInfo.Text = "接收到:" + receiveMessage + "-" +
DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
}
});
acceptThread.IsBackground = true;
acceptThread.Start();
}
}
}Code language: C# (cs)
基于 WinForms + TcpClient / TcpListener 实现:
客户端持续输入自定义文本发送给服务端,输入【退出】时断开连接、结束程序
代码演示用简单的方式解决多线程卡顿问题,但是更正确的应该是如下:
Control.CheckForIllegalCrossThreadCalls = false;属于不推荐的暴力写法,正规方案使用Invoke/BeginInvoke跨线程更新控件。
一、服务端
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
// 不推荐正式项目使用,仅学习演示
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
// 新开线程,防止UI阻塞
new Thread(() =>
{
IPAddress ip = IPAddress.Parse(textBoxIP.Text);
listener = new TcpListener(ip, Convert.ToInt32(textBoxPort.Text));
listener.Start();
AppendLog($"服务器启动-{DateTime.Now.ToShortTimeString()}");
tcpClient = listener.AcceptTcpClient();
AppendLog($"客户端连接成功-{DateTime.Now.ToShortTimeString()}");
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);
if (length <= 0)
{
AppendLog("客户端断开连接");
break;
}
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
AppendLog($"接收到:{receiveMessage} -{DateTime.Now.ToShortTimeString()}");
}
tcpClient.Close();
listener.Stop();
}).Start();
}
// 追加日志到文本框
private void AppendLog(string msg)
{
textBoxInfo.Text = msg + "\r\n" + textBoxInfo.Text;
}
}
}Code language: C# (cs)
二、客户端代码
实现【连续输入,输入“退出”结束】
客户端界面建议准备:
textBoxServerIp:服务端IPtextBoxPort:端口textBoxSend:输入待发送消息btnConnect:连接按钮btnSend:发送按钮
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpClientDemo
{
public partial class ClientForm : Form
{
private TcpClient client;
private NetworkStream stream;
private bool isConnected = false;
public ClientForm()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
// 连接服务器
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient();
client.Connect(textBoxServerIp.Text, Convert.ToInt32(textBoxPort.Text));
stream = client.GetStream();
isConnected = true;
MessageBox.Show("连接成功,可以开始发送消息!");
}
catch (Exception ex)
{
MessageBox.Show("连接失败:" + ex.Message);
}
}
// 发送消息核心逻辑
private void btnSend_Click(object sender, EventArgs e)
{
if (!isConnected)
{
MessageBox.Show("请先连接服务器!");
return;
}
string content = textBoxSend.Text.Trim();
if (string.IsNullOrEmpty(content))
return;
// 判断是否输入退出指令
if (content == "退出")
{
byte[] exitData = Encoding.Unicode.GetBytes(content);
stream.Write(exitData, 0, exitData.Length);
// 关闭资源
stream.Close();
client.Close();
isConnected = false;
MessageBox.Show("已断开连接");
return;
}
// 正常发送自定义内容
byte[] data = Encoding.Unicode.GetBytes(content);
stream.Write(data, 0, data.Length);
textBoxSend.Clear();
}
}
}Code language: C# (cs)
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 8899);
NetworkStream stream = client.GetStream();
while (true)
{
Console.Write("请输入发送内容:");
string msg = Console.ReadLine();
byte[] buf = Encoding.Unicode.GetBytes(msg);
stream.Write(buf,0,buf.Length);
if (msg == "退出")
{
stream.Close();
client.Close();
break;
}
}
}Code language: JavaScript (javascript)
如果你需要,我可以把整套代码改成纯异步async/await写法,彻底抛弃子线程+禁用跨线程检查这种不规范方式。