.NET下WPF学习之Socket通信

您所在的位置:网站首页 wpf异步编程 .NET下WPF学习之Socket通信

.NET下WPF学习之Socket通信

2023-08-16 09:04| 来源: 网络整理| 查看: 265

Socket通信 关于Socket

Socket作为进程通信的机制,是处于网络层中的应用层,说白了就是两个程序间通信用的。

它的形式与电话插座类似,电话的通话双方相当于两个互相通信的程序,电话号相当于IP。

 

网络通信三要素 IP地址(网络上主机设备的唯一标识,识别一台唯一的主机) 端口号(定位程序,确定两个通信的程序)

    有效端口:0~65535,其中0~1023由系统使用,称为公认端口,他们紧密绑定与一些服务。从1024~49151是一些松散的绑定于一些服务,需要注册的一些端口,称为注册端口,剩下的49152~65535为动态端口、私有端口,我们一般开发都是使用这一频段的端口.

传输协议(用什么样的方式进行交互)

       常见协议:TCP(面向连接,提供可靠的服务),UDP(无连接,传输速度快),一般使用TCP。

服务端于客户端Socket通信流程

 

 重点记忆两个端的步骤:

服务端:                                                                                         客户端:

1、创建Socket对象(负责侦听)               1、创建Socket对象

2、绑定端口                         2、连接服务器端

3、开启侦听                         3、发送消息、接受消息

4、开始接受客户端连接(不断接收,涉及多线程)        4、停止连接

5、创建一个代理Socket对象(负责通信)                     5、关闭Socket对象

6、发送、接收消息

7、关闭Socket对象

实现代码

服务端XAML代码(客户端类似):

1 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 服务端XAML(客户端与服务端相似)

具体服务端实现:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Net.Sockets; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 using System.Windows; 10 using System.Windows.Controls; 11 using System.Windows.Data; 12 using System.Windows.Documents; 13 using System.Windows.Input; 14 using System.Windows.Media; 15 using System.Windows.Media.Imaging; 16 using System.Windows.Navigation; 17 using System.Windows.Shapes; 18 19 namespace SocketDemo 20 { 21 /// 22 /// MainWindow.xaml 的交互逻辑 23 /// 24 public partial class MainWindow : Window 25 { 26 List clientScoketLis = new List();//存储连接服务器端的客户端的Socket 27 public MainWindow() 28 { 29 InitializeComponent(); 30 Loaded += MainWindow_Loaded; 31 btnStartServer.Click += BtnStartServer_Click;//事件注册 32 btnSendMsg.Click += BtnSendMsg_Click; 33 Closing += MainWindow_Closing; 34 } 35 36 37 private void MainWindow_Loaded(object sender, RoutedEventArgs e) 38 { 39 ClientWindows clientWindows = new ClientWindows(); 40 clientWindows.Show(); 41 } 42 /// 43 /// 关闭事件 44 /// 45 private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) 46 { 47 //使用foreach出现 “集合已修改;可能无法执行枚举操作”,ClientExit源于方法中对list集合进行了Remove,所造成的异常。 48 //msdn的解释:foreach 语句是对枚举数的包装,它只允许从集合中读取,不允许写入集合。也就是,不能在foreach里遍历的时侯把它的元素进行删除或增加的操作的 49 //foreach (var socket in clientScoketLis) 50 //{ 51 // ClientExit(null , socket); 52 //} 53 //改成for循环即可 54 for (int i = 0; i < clientScoketLis.Count; i++)//向每个客户端说我下线了 55 { 56 ClientExit(null, clientScoketLis[i]); 57 } 58 } 59 60 /// 61 /// 开启服务事件 62 /// 63 private void BtnStartServer_Click(object sender, RoutedEventArgs e) 64 { 65 //1、创建Socket对象 66 //参数:寻址方式,当前为Ivp4 指定套接字类型 指定传输协议Tcp; 67 Socket socket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp); 68 //2、绑定端口、IP 69 IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(this.txtIp.Text) , int.Parse(txtPort.Text)); 70 socket.Bind(iPEndPoint); 71 //3、开启侦听 10为队列最多接收的数量 72 socket.Listen(10);//如果同时来了100个连接请求,只能处理一个,队列中10个在等待连接的客户端,其他的则返回错误消息。 73 74 //4、开始接受客户端的连接 ,连接会阻塞主线程,故使用线程池。 75 ThreadPool.QueueUserWorkItem(new WaitCallback(AcceptClientConnect),socket); 76 77 78 } 79 /// 80 /// 线程池线程执行的接受客户端连接方法 81 /// 82 /// 传入的Socket 83 private void AcceptClientConnect(object obj) 84 { 85 //转换Socket 86 var serverSocket = obj as Socket; 87 88 AppendTxtLogText("服务端开始接收客户端连接!"); 89 90 //不断接受客户端的连接 91 while (true) 92 { 93 //5、创建一个负责通信的Socket 94 Socket proxSocket = serverSocket.Accept(); 95 AppendTxtLogText(string.Format("客户端:{0}连接上了!", proxSocket.RemoteEndPoint.ToString())); 96 //将连接的Socket存入集合 97 clientScoketLis.Add(proxSocket); 98 //6、不断接收客户端发送来的消息 99 ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveClientMsg) , proxSocket); 100 } 101 102 } 103 /// 104 /// 不断接收客户端信息子线程方法 105 /// 106 /// 参数Socke对象 107 private void ReceiveClientMsg(object obj) 108 { 109 var proxSocket = obj as Socket; 110 //创建缓存内存,存储接收的信息 ,不能放到while中,这块内存可以循环利用 111 byte[] data = new byte[1020*1024]; 112 while (true) 113 { 114 int len; 115 try 116 { 117 //接收消息,返回字节长度 118 len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None); 119 } 120 catch (Exception ex) 121 { 122 //7、关闭Socket 123 //异常退出 124 try 125 { 126 ClientExit(string.Format("客户端:{0}非正常退出", proxSocket.RemoteEndPoint.ToString()), proxSocket); 127 } 128 catch (Exception) 129 { 130 } 131 return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束 132 } 133 134 if (len 180 //{ 181 // this.txtLog.Text = string.Format("{0}\r\n{1}" , s , txtLog.Text); 182 //}) ,str); 183 //异步方法 184 this.Dispatcher.BeginInvoke(new Action(s => 185 { 186 this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text); 187 }), str); 188 } 189 else 190 { 191 this.txtLog.Text = string.Format("{0}\r\n{1}", str, txtLog.Text); 192 } 193 } 194 /// 195 /// 客户端退出调用 196 /// 197 /// 198 private void ClientExit(string msg , Socket proxSocket) 199 { 200 AppendTxtLogText(msg); 201 clientScoketLis.Remove(proxSocket);//移除集合中的连接Socket 202 203 try 204 { 205 if (proxSocket.Connected)//如果是连接状态 206 { 207 proxSocket.Shutdown(SocketShutdown.Both);//关闭连接 208 proxSocket.Close(100);//100秒超时间 209 } 210 } 211 catch (Exception ex) 212 { 213 } 214 } 215 } 216 } 服务器实现代码

具体客户端实现:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Net.Sockets; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 using System.Windows; 10 using System.Windows.Controls; 11 using System.Windows.Data; 12 using System.Windows.Documents; 13 using System.Windows.Input; 14 using System.Windows.Media; 15 using System.Windows.Media.Imaging; 16 using System.Windows.Shapes; 17 18 namespace SocketDemo 19 { 20 /// 21 /// ClientWindows.xaml 的交互逻辑 22 /// 23 public partial class ClientWindows : Window 24 { 25 private Socket _socket; 26 public ClientWindows() 27 { 28 InitializeComponent(); 29 btnSendMsg.Click += BtnSendMsg_Click;//注册事件 30 btnConnect.Click += BtnConnect_Click; 31 Closing += ClientWindows_Closing; 32 } 33 /// 34 /// 窗口关闭事件 35 /// 36 private void ClientWindows_Closing(object sender, System.ComponentModel.CancelEventArgs e) 37 { 38 ServerExit(null,_socket);//向服务端说我下线了。 39 } 40 41 /// 42 /// 连接按钮事件 43 /// 44 private void BtnConnect_Click(object sender, RoutedEventArgs e) 45 { 46 //1、创建Socket对象 47 Socket socket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp); 48 _socket = socket; 49 //2、连接服务器,绑定IP 与 端口 50 IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(txtIp.Text) , int.Parse(txtPort.Text)); 51 try 52 { 53 socket.Connect(iPEndPoint); 54 } 55 catch (Exception) 56 { 57 MessageBox.Show("连接失败,请重新连接!","提示"); 58 return; 59 } 60 //3、接收消息 61 ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveServerMsg),socket); 62 } 63 64 /// 65 /// 不断接收客户端信息子线程方法 66 /// 67 /// 参数Socke对象 68 private void ReceiveServerMsg(object obj) 69 { 70 var proxSocket = obj as Socket; 71 //创建缓存内存,存储接收的信息 ,不能放到while中,这块内存可以循环利用 72 byte[] data = new byte[1020 * 1024]; 73 while (true) 74 { 75 int len; 76 try 77 { 78 //接收消息,返回字节长度 79 len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None); 80 } 81 catch (Exception ex) 82 { 83 //7、关闭Socket 84 //异常退出 85 try 86 { 87 ServerExit(string.Format("服务端:{0}非正常退出", proxSocket.RemoteEndPoint.ToString()), proxSocket); 88 } 89 catch (Exception) 90 { 91 92 } 93 return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束 94 } 95 96 if (len 158 //{ 159 // this.txtLog.Text = string.Format("{0}\r\n{1}" , s , txtLog.Text); 160 //}) ,str); 161 //异步方法 162 this.Dispatcher.BeginInvoke(new Action(s => 163 { 164 this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text); 165 }), str); 166 } 167 else 168 { 169 this.txtLog.Text = string.Format("{0}\r\n{1}", str, txtLog.Text); 170 } 171 } 172 } 173 } 客户端实现代码 运行展示:

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3