一、C#Tcp通信实现
C#使用Socket实现Tcp通信,创建服务端、客户端窗体。
服务端:打开后侦听客户端连接,将客户端终端地址保存,可以选择指定终端发送,可群发。
客户端:连接服务端后,可收发数据。
二、案例展示
三、CS代码
3.1 服务端界面
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CSharpeDemo.Demo_TcpProtocol
{
public partial class Frm_TcpServer : Form
{
TcpServerTool tcpServerTool;
#region 窗体:初始化、加载、关闭
public Frm_TcpServer()
{
InitializeComponent();
}
private void Frm_TcpClient_Load(object sender, EventArgs e)
{
ControlStyleUpdata(picBox_ConnectStatu, Color.Gray);
}
private void Frm_TcpServer_FormClosing(object sender, FormClosingEventArgs e)
{
if (tcpServerTool != null)
{
tcpServerTool.Disconnect();
}
}
#endregion
#region 控件圆角方法
public void ControlStyleUpdata(Control control)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(control.ClientRectangle);
Region region = new Region(gp);
control.Region = region;
gp.Dispose();
region.Dispose();
}
public void ControlStyleUpdata(Control control, Color bcColor)
{
control.BackColor = bcColor;
ControlStyleUpdata(control);
}
#endregion
#region 鼠标单击事件
private void btn_Open_Click(object sender, EventArgs e)
{
bool isOpen = btn_Open.Text.Equals("打开") ? true : false;
if (isOpen)
{
tcpServerTool = new TcpServerTool(tbx_IpAddress.Text, tbx_Port.Text);
tcpServerTool.ExecuteMessageChanged += TcpTool_ExecuteMessageChangedCallback;
tcpServerTool.ClientCountChanged += TcpTool_OnCountChangedCallback;
tcpServerTool.Open();
}
else
{
tcpServerTool.Disconnect();
}
if (tcpServerTool.IsListened) picBox_ConnectStatu.BackColor = Color.LimeGreen;
else picBox_ConnectStatu.BackColor = Color.Gray;
btn_Open.Text = tcpServerTool.IsListened ? "关闭" : "打开";
}
private void btn_Send_Click(object sender, EventArgs e)
{
if (tcpServerTool != null)
{
if (checkBox_SendGroup.Checked)
{
tcpServerTool.SendGroup(rtbx_SendData.Text);
}
else
{
tcpServerTool.Send(cbx_ClientList.Text, rtbx_SendData.Text);
}
}
}
private void btn_ClearReceiveData_Click(object sender, EventArgs e)
{
rtbx_ReceiveData.Text = string.Empty;
}
private void btn_ClearSendData_Click(object sender, EventArgs e)
{
rtbx_SendData.Text = string.Empty;
}
#endregion
private void TcpTool_ExecuteMessageChangedCallback(object sender, string message)
{
MessageShow(message);
}
public void TcpTool_OnCountChangedCallback(object sender, string endPoint)
{
MessageShow($"{sender}:{endPoint}");
ClientListUpdata(endPoint, sender.ToString());
}
public void MessageShow(string data)
{
rtbx_ReceiveData.Invoke(new Action(() =>
{
rtbx_ReceiveData.AppendText($"{DateTime.Now}】{data}{System.Environment.NewLine}");
}));
}
public void ClientListUpdata(string endPoint, string mode)
{
cbx_ClientList.Invoke(new Action(() =>
{
switch (mode.ToString().ToLower())
{
case "add":
cbx_ClientList.Items.Add(endPoint);
break;
case "remove":
cbx_ClientList.Items.Remove(endPoint);
break;
default:
break;
}
if (cbx_ClientList.Items.Count==1) cbx_ClientList.SelectedIndex = 0;
if (cbx_ClientList.Items.Count == 0) cbx_ClientList.Text = string.Empty;
}));
}
}
}
3.2 服务端辅助类
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TIBCO.Rendezvous;
using ZXing;
namespace CSharpeDemo.Demo_TcpProtocol
{
public class TcpServerTool
{
#region 事件委托
public event EventHandler<string> ExecuteMessageChanged;
public event EventHandler<string> ClientCountChanged;
#endregion
#region 字段、属性
private string _ip = "127.0.0.1";
private int _port = 9000;
private string _ipPort = "127.0.0.1:9000";
private bool _isConnected = false;
private bool _isListened = false;
private NetworkStream _stream;
private Socket _serverSocket;
private Thread listenThread = null;
private List<string> _clientIpPortList = new List<string>();
private List<Socket> _clientSocketList = new List<Socket>();
private List<Thread> _clientSocketThreadList = new List<Thread>();
public string IP { get => _ip; set => _ip = value; }
public int Port { get => _port; set => _port = value; }
public bool IsConnected { get => _isConnected; set => _isConnected = value; }
public bool IsListened { get => _isListened; set => _isListened = value; }
public NetworkStream Stream { get => _stream; set => _stream = value; }
public Socket ServerSocket { get => _serverSocket; set => _serverSocket = value; }
public List<string> ClientIpPortList { get => _clientIpPortList; set => _clientIpPortList = value; }
public List<Socket> ClientSocketList { get => _clientSocketList; set => _clientSocketList = value; }
public List<Thread> ClientSocketThreadList { get => _clientSocketThreadList; set => _clientSocketThreadList = value; }
public string IpPort { get => _ipPort; set => _ipPort = value; }
#endregion
#region 构造方法
public TcpServerTool(string ip, int port)
{
this.IP = ip;
this.Port = port;
}
public TcpServerTool(string ip, string port)
{
this.IP = ip;
if (int.TryParse(port, out int portStr))
{
this.Port = portStr;
}
}
#endregion
public void Disconnect()
{
IsListened = false;
IsConnected = false;
foreach (Thread item in ClientSocketThreadList)
{
item.Abort();
}
foreach (Socket item in ClientSocketList)
{
item.Close();
}
listenThread?.Abort();
listenThread = null;
Stream?.Close();
ServerSocket?.Close();
ServerSocket = null;
Stream = null;
ClientSocketThreadList?.Clear();
ClientSocketList?.Clear();
ClientIpPortList?.Clear();
}
public void Open()
{
try
{
IPAddress ipAddress = IPAddress.Parse(IP);
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ServerSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Port);
ServerSocket.Bind(localEndPoint);
ExecuteMessageChanged?.Invoke(this, $"开始侦听准备...");
ServerSocket.Listen(10);
listenThread = new Thread(OnListenClient);
listenThread.IsBackground = true;
listenThread.Start();
IsListened = true;
ExecuteMessageChanged?.Invoke(this, $"本地终端:{ServerSocket.LocalEndPoint}");
ExecuteMessageChanged?.Invoke(this, $"协议:{ServerSocket.LocalEndPoint.AddressFamily}");
ExecuteMessageChanged?.Invoke(this, $"准备完成,开始侦听客户端连接...");
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"创建连接失败....");
ExecuteMessageChanged?.Invoke(this, $"{ex.Message}");
}
}
public void OnListenClient()
{
try
{
while (true)
{
Socket socket = ServerSocket.Accept();
ExecuteMessageChanged?.Invoke(this, $"收到来自【{socket.LocalEndPoint}】远程终端的连接请求...");
string sendTestData = "Test Connect...";
ExecuteMessageChanged?.Invoke(this, $"尝试发送数据:{sendTestData}");
Send(socket, sendTestData);
Thread thread = new Thread(Received);
thread.Name = (ClientSocketThreadList.Count + 1) + "";
thread.IsBackground = true;
thread.Start(socket);
ClientIpPortList.Add(socket.RemoteEndPoint.ToString());
ClientSocketList.Add(socket);
ClientSocketThreadList.Add(thread);
ClientCountChanged?.Invoke("Add", socket.RemoteEndPoint.ToString());
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"侦听异常:{ex.Message}");
}
}
public void Received(object socketClientPara)
{
Socket socketServer = socketClientPara as Socket;
string remoteEndPoint = socketServer.RemoteEndPoint.ToString(); ;
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024];
if (socketServer == null) break;
int dataLength = socketServer.Receive(buffer);
string dataReceived = Encoding.ASCII.GetString(buffer, 0, dataLength);
ExecuteMessageChanged.Invoke(this, "接收数据:");
ExecuteMessageChanged.Invoke(this, $"{socketServer.RemoteEndPoint}->{dataReceived}");
}
catch (Exception ex)
{
if (IsListened)
{
ClientIpPortList.Remove(remoteEndPoint);
ClientCountChanged?.Invoke("Remove", remoteEndPoint);
Stream = null;
ExecuteMessageChanged.Invoke(this, "客户端已断开连接!");
ExecuteMessageChanged.Invoke(this, $"接收异常:{ex.Message}");
ClientSocketList.Find(s => s.RemoteEndPoint.Equals(remoteEndPoint))?.Close();
ClientSocketList.Remove(socketServer);
break;
}
}
}
}
public void Send(string ipPort, string data)
{
try
{
if (IsListened)
{
string socketIpPort = ClientIpPortList.Find(s => s.Equals(ipPort));
Socket socket = ClientSocketList.Find(s => s.RemoteEndPoint.ToString().Equals(ipPort));
if (socket !=null)
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
else
{
ExecuteMessageChanged?.Invoke(this, $"发送失败!socket = null");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"发送异常:{ex.Message}");
}
}
public void Send(Socket socket,string data)
{
try
{
if (IsListened)
{
if (Stream != null)
{
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
else
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"发送异常:{ex.Message}");
}
}
public void SendGroup(string data)
{
try
{
if (IsListened)
{
foreach (Socket socket in ClientSocketList)
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged.Invoke(this, $"发送到终端:{socket.RemoteEndPoint}");
ExecuteMessageChanged.Invoke(this, $"协议版本:{socket.RemoteEndPoint.AddressFamily}");
ExecuteMessageChanged.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"发送异常:{ex.Message}");
}
}
}
}
3.3 客户端界面
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CSharpeDemo.Demo_TcpProtocol
{
public partial class Frm_TcpClient :Form
{
TcpClientTool tcpTool;
#region 窗体:初始化、加载、关闭
public Frm_TcpClient()
{
InitializeComponent();
}
private void Frm_TcpClient_Load(object sender, EventArgs e)
{
ControlStyleUpdata(picBox_ConnectStatu, Color.Gray);
}
private void Frm_TcpClient_FormClosing(object sender, FormClosingEventArgs e)
{
tcpTool?.Disconnect();
tcpTool = null;
}
#endregion
#region 鼠标单击事件
private void btn_Connect_Click(object sender, EventArgs e)
{
bool isOpen = btn_Connect.Text.Equals("连接") ? true : false;
if (isOpen)
{
tcpTool = new TcpClientTool(tbx_IpAddress.Text, tbx_Port.Text);
tcpTool.ExecuteMessageChanged += TcpTool_ExecuteMessageCallBack;
tcpTool.Connect();
}
else
{
tcpTool.Disconnect();
}
if (tcpTool.IsConnected) picBox_ConnectStatu.BackColor = Color.LimeGreen;
else picBox_ConnectStatu.BackColor = Color.Gray;
btn_Connect.Text = tcpTool.IsConnected ? "断开" : "连接";
}
private void btn_Send_Click(object sender, EventArgs e)
{
if (tcpTool != null)
{
tcpTool.Send(rtbx_SendData.Text);
}
}
private void btn_ClearReceiveData_Click(object sender, EventArgs e)
{
rtbx_ReceiveData.Text = string.Empty;
}
private void btn_ClearSendData_Click(object sender, EventArgs e)
{
rtbx_SendData.Text = string.Empty;
}
#endregion
#region 控件圆角方法
public void ControlStyleUpdata(Control control)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(control.ClientRectangle);
Region region = new Region(gp);
control.Region = region;
gp.Dispose();
region.Dispose();
}
public void ControlStyleUpdata(Control control, Color bcColor)
{
control.BackColor = bcColor;
ControlStyleUpdata(control);
}
#endregion
private void TcpTool_ExecuteMessageCallBack(object sender, string e)
{
MessageShow(e);
}
public void MessageShow(string data)
{
rtbx_ReceiveData.Invoke(new Action(() =>
{
rtbx_ReceiveData.AppendText($"{DateTime.Now}】{data}{System.Environment.NewLine}");
}));
}
}
}
3.4 客户端辅助类
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZXing;
namespace CSharpeDemo.Demo_TcpProtocol
{
public class TcpClientTool
{
#region 字段、属性
private string _ip = "127.0.0.1";
private int _port = 8000;
private string _ipPort = "127.0.0.1:8000";
private bool _isConnected = false;
private Socket _clientSocket;
private Thread receiveThread = null;
public string IP { get => _ip; set => _ip = value; }
public int Port { get => _port; set => _port = value; }
public string IpPort { get => _ipPort; set => _ipPort = value; }
public bool IsConnected { get => _isConnected; set => _isConnected = value; }
public Socket ClientSocket { get => _clientSocket; set => _clientSocket = value; }
#endregion
#region 事件委托
public event EventHandler<string> ExecuteMessageChanged;
#endregion
public TcpClientTool(string ip, string port)
{
this.IP = ip;
if (int.TryParse(port, out int portStr))
{
this.Port = portStr;
}
}
public void Connect()
{
try
{
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipaddress = IPAddress.Parse(this.IP);
IPEndPoint endpoint = new IPEndPoint(ipaddress, Port);
ClientSocket.Connect(endpoint);
IsConnected = true;
ExecuteMessageChanged.Invoke(this, $"连接成功!");
Send("How are you!");
receiveThread = new Thread(Received);
receiveThread.IsBackground = true;
receiveThread.Start();
}
catch (Exception ex)
{
receiveThread?.Abort();
receiveThread = null;
ClientSocket.Close();
IsConnected = false;
ExecuteMessageChanged.Invoke(this, $"连接失败!{ex.Message}");
}
}
public void Disconnect()
{
ClientSocket.Close();
receiveThread?.Abort();
receiveThread = null;
IsConnected = false;
ExecuteMessageChanged.Invoke(this, $"断开连接!");
}
public void Send(string data)
{
try
{
byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(data);
ClientSocket.Send(arrClientSendMsg);
ExecuteMessageChanged.Invoke(this, data);
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"发送失败:{ex.Message}");
}
}
public void Received()
{
try
{
while (true)
{
byte[] arrRecMsg = new byte[1024 * 1024];
int length = ClientSocket.Receive(arrRecMsg);
string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length);
ExecuteMessageChanged.Invoke(this, $"{ClientSocket.RemoteEndPoint}->:{strRecMsg}");
}
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"远程服务器已中断连接...{ex.Message}");
}
}
}
}
3.4 界面整合
using CSharpeDemo.Demo_TcpProtocol2;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CSharpeDemo.Demo_TcpProtocol
{
public partial class Form_TcpTest : Form
{
Frm_TcpClient tcpClient;
Frm_TcpServer tcpServer;
public Form_TcpTest()
{
InitializeComponent();
this.MinimumSize = new System.Drawing.Size(850, 625);
}
private void btn_TCPServer_Click(object sender, EventArgs e)
{
label_CurrentWinName.Text = (sender as Button).Text;
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
}
private void btn_TCPClient_Click(object sender, EventArgs e)
{
label_CurrentWinName.Text = (sender as Button).Text;
if (tcpClient == null)
{
tcpClient = new Frm_TcpClient();
}
panel_Container.Controls.Clear();
tcpClient.TopLevel = false;
tcpClient.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpClient.Width;
tcpClient.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpClient);
tcpClient.Show();
}
private void Form_TcpTest_Load(object sender, EventArgs e)
{
label_CurrentWinName.Text = btn_TCPServer.Text;
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
}
private void Form_TcpTest_FormClosing(object sender, FormClosingEventArgs e)
{
tcpClient?.Close();
tcpServer?.Close();
}
}
}