C# Socket通信
一、通信协议 TCP/UDP
TCP
传输控制协议Transmission Control Protocol是一种面向连接的、可靠的、基于字节流的运输层通信协议,在简化的计算机网络OSI模型中,它完成传输层所指定的功能。优点传输安全,缺点效率相对低。
UDP
用户数据报协议 User Datagram ProtocolUDP是一个简单的面向无连接的,不可靠的数据报的传输层(transport layer)协议。优点传输速度快,缺点不安全。
二、SOCKET
socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。Socket是面向客户/服务器模型而设计的。通信的一方扮演客户机的角色,另一方扮演服务器的角色。服务器在运行中一直监听套接字指定的传输层端口,并等待着客户机的连接请求。当服务器端收到客户机发来的连接请求以后,服务器会接受客户机的连接请求,双方建立连接后,就可进行数据的传递。服务器端可以一对多。
支持TCP/UDP传输协议
IP找设备,port端口找到服务器上要通讯的程序。
建立socket对象,负责收发数据
三、SOCKET代码实现
客户端
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp7 { public partial class Form1 : Form { private Socket socket; Encoding encoding = Encoding.Unicode; public Form1() { InitializeComponent(); load(); } /// <summary> /// 加载 /// </summary> private void load() { //1.获取本地网络分配给你的IP IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName()); //第二步: foreach (var item in hostEntry.AddressList) { //3.判断是否是协议版本V4 if (item.AddressFamily == AddressFamily.InterNetwork) { cB_IPs.Items.Add(item); } } //添加本机IP cB_IPs.Items.Add("127.0.0.1"); cB_IPs.Items.Add("192.168.110.96"); cB_IPs.SelectedIndex = 0;//默认选中0个对象 } /// <summary> /// 连接 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button2_Click(object sender, EventArgs e) { //第一步:初始化套接字对象 socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); try { //第二步:连接 socket.Connect(cB_IPs.Text,(int)numericUpDown1.Value); MessageBox.Show("连接成功!"); Task.Run(() => { while (true) { //监测服务器是否下线 try { bool yes = socket.Poll(1, SelectMode.SelectRead); if (yes) { MessageBox.Show("服务器已下线!"); continue; } Reception(); } catch (Exception ex) { MessageBox.Show("服务器连接异常!"+ex.Message); return; } } }); } catch(Exception ex) { //连接失败 MessageBox.Show($"连接失败:{ex}"); } } /// <summary> /// 断开 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button1_Click(object sender, EventArgs e) { if (socket != null && socket.Connected) { socket.Close(); MessageBox.Show("断开连接"); } } /// <summary> /// 发送 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button3_Click(object sender, EventArgs e) { //1.判断连接状态 if (socket != null && socket.Connected) { //2.字符串转换二进制 byte[] data = encoding.GetBytes(richTextBox2.Text); try { //3.发送 socket.Send(data); } catch (Exception ex) { MessageBox.Show($"发送失败:{ex}"); } } } /// <summary> /// 接收数据 /// </summary> public void Reception() { byte[] data = new byte[1024 * 2]; try { //接收 int length = socket.Receive(data); //判断是否有发送字节 if (length > 0) { richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText($" [{DateTime.Now.ToString("HH:mm:ss")}]:{encoding.GetString(data, 0, length)}" + Environment.NewLine); })); } } catch (Exception ex) { MessageBox.Show($"接收失败:{ex}"); } } /// <summary> /// 打开服务器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button4_Click(object sender, EventArgs e) { Form2 form2 = new Form2(); form2.Show(); } } }
服务端
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp7 { public partial class Form2 : Form { //服务器套接字 private Socket socket; //客户端连接 List<Socket> sockets = new List<Socket>(); //服务器连接标识 bool connectingFlag; Encoding encoding = Encoding.Unicode; public Form2() { InitializeComponent(); load(); } private void Label3_Click(object sender, EventArgs e) { } /// <summary> /// 加载 /// </summary> private void load() { //1.获取本地网络分配给你的IP System.Net.IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName()); //第二步: foreach (var item in hostEntry.AddressList) { //3.判断是否是协议版本V4 if (item.AddressFamily == AddressFamily.InterNetwork) { cB_IPs.Items.Add(item); } } //添加本机IP cB_IPs.Items.Add("127.0.0.1"); cB_IPs.Items.Add("192.168.110.96"); cB_IPs.SelectedIndex = 0;//默认选中0个对象 } /// <summary> /// 打开服务器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button2_Click(object sender, EventArgs e) { //1.初始化 socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); //2.监听 IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(cB_IPs.Text) ,(int)numericUpDown1.Value); try { socket.Bind(iPEndPoint);//监听 socket.Listen(10);//一秒可以监听多少个客户端连接 MessageBox.Show("服务器打开成功"); connectingFlag = true; #region 监视客户端 //监听客户端 ThreadPool.QueueUserWorkItem((Object o) => { while (true) { //判断服务器是否连接 if (!connectingFlag) { break; } Socket socket1 = socket.Accept();//客户端连接 sockets.Add(socket1); //获取客户端连接IP和端口 IPEndPoint iPEndPoint1 = (IPEndPoint)socket1.RemoteEndPoint; //显示到数据表格 dataGridView1.Invoke(new Action(() => { dataGridView1.Rows.Add(iPEndPoint1.Address, iPEndPoint1.Port); })); } }); #endregion #region 监视客户端发送数据 Task.Run(() => { while (true) { //判断服务器是否连接 if (!connectingFlag) { break; } //1.判断是否有客户端 if (sockets.Count == 0) { continue; } //2.循环监视客户端 for (int i = sockets.Count-1; i >=0; i--) { //3.判断用户是否下线 bool downStatus = sockets[i].Poll(1,SelectMode.SelectRead); //true下线 if (downStatus) { dataGridView1.Invoke(new Action(() => { dataGridView1.Rows.RemoveAt(i);//删除显示 })); sockets.RemoveAt(i);//删除客户端 continue; } try { //4.接收用户信息 byte[] data = new byte[1024]; int dataLength = sockets[i].Receive(data); //判断用户是否发送数据 if (dataLength > 0) { //解析用户发送数据 string send = encoding.GetString(data); //获取发送用户ip和端口 IPEndPoint iPEndPoint1 = (IPEndPoint)sockets[i].RemoteEndPoint; //显示发送信息 richTextBox2.Invoke(new Action(() => { richTextBox2.AppendText($"{iPEndPoint1.Address} [{DateTime.Now.ToString("HH:mm:ss")}]:{encoding.GetString(data, 0, dataLength)}" + Environment.NewLine); })); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } }); #endregion } catch (Exception ex) { MessageBox.Show($"服务端开始失败:{ex}"); } } /// <summary> /// 发送 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button3_Click(object sender, EventArgs e) { try { //判断是否群发 int index = dataGridView1.CurrentCell.RowIndex; //判断是否群发 if (checkBox1.Checked) { foreach (Socket item in sockets) { item.Send(encoding.GetBytes(richTextBox1.Text)); } } else { //获取客户端socket Socket socket = sockets[index]; //发送 socket.Send(encoding.GetBytes(richTextBox1.Text)); } } catch (Exception ex) { MessageBox.Show($"发送失败:{ex}"); } } /// <summary> /// 断开服务器连接 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button1_Click(object sender, EventArgs e) { if (connectingFlag) { connectingFlag = false; sockets.Clear();//清除集合 dataGridView1.Rows.Clear();//清除显示 socket.Close();//关闭服务器 } } } }