博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET下WPF学习之Socket通信
阅读量:6171 次
发布时间:2019-06-21

本文共 14557 字,大约阅读时间需要 48 分钟。

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 try116 {117 //接收消息,返回字节长度118 len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);119 }120 catch (Exception ex)121 {122 //7、关闭Socket123 //异常退出124 try125 {126 ClientExit(string.Format("客户端:{0}非正常退出", proxSocket.RemoteEndPoint.ToString()), proxSocket);127 }128 catch (Exception)129 {130 }131 return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束132 }133 134 if (len <= 0)//判断接收的字节数135 {136 //7、关闭Socket137 //小于0表示正常退出138 try139 {140 ClientExit(string.Format("客户端:{0}正常退出", proxSocket.RemoteEndPoint.ToString()), proxSocket);141 }142 catch (Exception)143 {144 }145 return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束146 }147 //将消息显示到TxtLog148 string msgStr = Encoding.Default.GetString(data , 0 , len);149 //拼接字符串150 AppendTxtLogText(string.Format("接收到客户端:{0}的消息:{1}" , proxSocket.RemoteEndPoint.ToString() , msgStr));151 }152 }153 154 ///
155 /// 消息发送事件156 /// 157 private void BtnSendMsg_Click(object sender, RoutedEventArgs e)158 {159 foreach (Socket proxSocket in clientScoketLis)160 {161 if (proxSocket.Connected)//判断客户端是否还在连接162 {163 byte[] data = Encoding.Default.GetBytes(this.txtMsg.Text);164 //6、发送消息165 proxSocket.Send(data , 0 , data.Length , SocketFlags.None); //指定套接字的发送行为166 this.txtMsg.Text = null;167 }168 }169 }170 ///
171 /// 向文本框中追加信息172 /// 173 ///
174 private void AppendTxtLogText( string str)175 {176 if (!(txtLog.Dispatcher.CheckAccess()))//判断跨线程访问177 {178 ////同步方法179 //this.Dispatcher.Invoke(new Action
( s => 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 else190 { 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);//移除集合中的连接Socket202 203 try204 {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 <= 0)//判断接收的字节数 97                 { 98                     //7、关闭Socket 99                     //小于0表示正常退出100                     try101                     {102                         ServerExit(string.Format("服务端:{0}正常退出", proxSocket.RemoteEndPoint.ToString()), proxSocket);103                     }104                     catch (Exception)105                     {106 107                     }108                     return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束109                 }110                 //将消息显示到TxtLog111                 string msgStr = Encoding.Default.GetString(data, 0, len);112                 //拼接字符串113                 AppendTxtLogText(string.Format("接收到服务端:{0}的消息:{1}", proxSocket.RemoteEndPoint.ToString(), msgStr));114             }115         }116 117         /// 118         /// 客户端退出调用119         /// 120         /// 121         private void ServerExit(string msg, Socket proxSocket)122         {123             AppendTxtLogText(msg);124             try125             {126                 if (proxSocket.Connected)//如果是连接状态127                 {128                     proxSocket.Shutdown(SocketShutdown.Both);//关闭连接129                     proxSocket.Close(100);//100秒超时间130                 }131             }132             catch (Exception ex)133             {134             }135         }136 137         /// 138         /// 发送信息按钮事件139         /// 140         private void BtnSendMsg_Click(object sender, RoutedEventArgs e)141         {142             byte[] data = Encoding.Default.GetBytes(this.txtMsg.Text);143             //6、发送消息144             _socket.Send(data, 0, data.Length, SocketFlags.None); //指定套接字的发送行为145             this.txtMsg.Text = null;146         }147 148         /// 149         /// 向文本框中追加信息150         /// 151         /// 152         private void AppendTxtLogText(string str)153         {154             if (!(txtLog.Dispatcher.CheckAccess()))//判断跨线程访问155             {156                 ////同步方法157                 //this.Dispatcher.Invoke(new Action
( s => 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 else168 {169 this.txtLog.Text = string.Format("{0}\r\n{1}", str, txtLog.Text);170 }171 }172 }173 }
客户端实现代码

运行展示:

 

转载于:https://www.cnblogs.com/memoyu/p/10764884.html

你可能感兴趣的文章
Dev GridControl导出
查看>>
开始翻译Windows Phone 8 Development for Absolute Beginners教程
查看>>
Python tablib模块
查看>>
站立会议02
查看>>
Windows和Linux如何使用Java代码实现关闭进程
查看>>
0428继承性 const static
查看>>
第一课:从一个简单的平方根运算学习平方根---【重温数学】
查看>>
NET反射系统
查看>>
Oracle12C本地用户的创建和登录
查看>>
使用JS制作一个鼠标可拖的DIV(一)——鼠标拖动
查看>>
HDU problem 5635 LCP Array【思维】
查看>>
leetcode10. 正则表达式匹配
查看>>
redis常用命令--zsets
查看>>
springcloud--Feign(WebService客户端)
查看>>
网络攻击
查看>>
sorting, two pointers(cf div.3 1113)
查看>>
Scala并发编程【消息机制】
查看>>
win10下安装Oracle 11g 32位客户端遇到INS-13001环境不满足最低要求
查看>>
AngularJS-01.AngularJS,Module,Controller,scope
查看>>
【MySQL 安装过程1】顺利安装MySQL完整过程
查看>>