C#的socket

四:SOCKET通信基本流程图:

C#的socket

根据socket通信基本流程图,总结通信的基本步骤:

服务器端:

第一步:创建一个用于监听连接的Socket对像;

第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;

第三步:用socket对像的Bind()方法绑定EndPoint;

第四步:用socket对像的Listen()方法开始监听;

第五步:接收到客户端的连接,用socket对像的Accept()方法创建一个新的用于和客户端进行通信的socket对像;

第六步:通信结束后一定记得关闭socket;

客户端:

第一步:建立一个Socket对像;

第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;

第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;

第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;

第五步:用socket对像的Receive()方法接受服务器发来的信息 ;

第六步:通信结束后一定记得关闭socket;

服务端界面:

C#的socket

代码实现如下:

C#的socket

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Net;
  8 using System.Net.Sockets;
  9 using System.Text;
 10 using System.Threading.Tasks;
 11 using System.Windows.Forms;
 12 using System.Threading;
 13 using System.IO;
 14 
 15 namespace SocketServer
 16 {
 17     public partial class FrmServer : Form
 18     {
 19         public FrmServer()
 20         {
 21             InitializeComponent();
 22         }
 23 
 24         //定义回调:解决跨线程访问问题
 25         private delegate void SetTextValueCallBack(string strValue);
 26         //定义接收客户端发送消息的回调
 27         private delegate void ReceiveMsgCallBack(string strReceive);
 28         //声明回调
 29         private SetTextValueCallBack setCallBack;
 30         //声明
 31         private ReceiveMsgCallBack receiveCallBack;
 32         //定义回调:给ComboBox控件添加元素
 33         private delegate void SetCmbCallBack(string strItem);
 34         //声明
 35         private SetCmbCallBack setCmbCallBack;
 36         //定义发送文件的回调
 37         private delegate void SendFileCallBack(byte[] bf);
 38         //声明
 39         private SendFileCallBack sendCallBack;
 40 
 41         //用于通信的Socket
 42         Socket socketSend;
 43         //用于监听的SOCKET
 44         Socket socketWatch;
 45 
 46         //将远程连接的客户端的IP地址和Socket存入集合中
 47         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
 48 
 49         //创建监听连接的线程
 50         Thread AcceptSocketThread;
 51         //接收客户端发送消息的线程
 52         Thread threadReceive;
 53 
 54         /// <summary>
 55         /// 开始监听
 56         /// </summary>
 57         /// <param name="sender"></param>
 58         /// <param name="e"></param>
 59         private void btn_Start_Click(object sender, EventArgs e)
 60         {
 61             //当点击开始监听的时候 在服务器端创建一个负责监听IP地址和端口号的Socket
 62             socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 63             //获取ip地址
 64             IPAddress ip=IPAddress.Parse(this.txt_IP.Text.Trim());
 65             //创建端口号
 66             IPEndPoint point=new IPEndPoint(ip,Convert.ToInt32(this.txt_Port.Text.Trim()));
 67             //绑定IP地址和端口号
 68             socketWatch.Bind(point);
 69             this.txt_Log.AppendText("监听成功"+" \r \n");
 70             //开始监听:设置最大可以同时连接多少个请求
 71             socketWatch.Listen(10);
 72 
 73             //实例化回调
 74             setCallBack = new SetTextValueCallBack(SetTextValue);
 75             receiveCallBack = new ReceiveMsgCallBack(ReceiveMsg);
 76             setCmbCallBack = new SetCmbCallBack(AddCmbItem);
 77             sendCallBack = new SendFileCallBack(SendFile);
 78 
 79             //创建线程
 80             AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListen));
 81             AcceptSocketThread.IsBackground = true;
 82             AcceptSocketThread.Start(socketWatch);
 83         }
 84 
 85         /// <summary>
 86         /// 等待客户端的连接,并且创建与之通信用的Socket
 87         /// </summary>
 88         /// <param name="obj"></param>
 89         private void StartListen(object obj)
 90         {
 91             Socket socketWatch = obj as Socket;
 92             while (true)
 93             {               
 94                 //等待客户端的连接,并且创建一个用于通信的Socket
 95                 socketSend = socketWatch.Accept();
 96                 //获取远程主机的ip地址和端口号
 97                 string strIp=socketSend.RemoteEndPoint.ToString();
 98                 dicSocket.Add(strIp, socketSend);
 99                 this.cmb_Socket.Invoke(setCmbCallBack, strIp);
100                 string strMsg = "远程主机:" + socketSend.RemoteEndPoint + "连接成功";
101                 //使用回调
102                 txt_Log.Invoke(setCallBack, strMsg);
103 
104                 //定义接收客户端消息的线程
105                 Thread threadReceive = new Thread(new ParameterizedThreadStart(Receive));
106                 threadReceive.IsBackground = true;
107                 threadReceive.Start(socketSend);
108 
109             }
110         }
111 
112        
113 
114         /// <summary>
115         /// 服务器端不停的接收客户端发送的消息
116         /// </summary>
117         /// <param name="obj"></param>
118         private void Receive(object obj)
119         {
120             Socket socketSend = obj as Socket;
121             while (true)
122             {
123                 //客户端连接成功后,服务器接收客户端发送的消息
124                 byte[] buffer = new byte[2048];
125                 //实际接收到的有效字节数
126                 int count = socketSend.Receive(buffer);
127                 if (count == 0)//count 表示客户端关闭,要退出循环
128                 {
129                     break;
130                 }
131                 else
132                 {
133                     string str = Encoding.Default.GetString(buffer, 0, count);
134                     string strReceiveMsg = "接收:" + socketSend.RemoteEndPoint + "发送的消息:" + str;
135                     txt_Log.Invoke(receiveCallBack, strReceiveMsg);
136                 }
137             }
138         }
139 
140         /// <summary>
141         /// 回调委托需要执行的方法
142         /// </summary>
143         /// <param name="strValue"></param>
144         private void SetTextValue(string strValue)
145         {
146             this.txt_Log.AppendText(strValue + " \r \n");
147         }
148 
149 
150         private void ReceiveMsg(string strMsg)
151         {
152             this.txt_Log.AppendText(strMsg + " \r \n");
153         }
154 
155         private void AddCmbItem(string strItem)
156         {
157             this.cmb_Socket.Items.Add(strItem);
158         }
159 
160         /// <summary>
161         /// 服务器给客户端发送消息
162         /// </summary>
163         /// <param name="sender"></param>
164         /// <param name="e"></param>
165         private void btn_Send_Click(object sender, EventArgs e)
166         {
167             try
168             {
169                 string strMsg = this.txt_Msg.Text.Trim();
170                 byte[] buffer = Encoding.Default.GetBytes(strMsg);
171                 List<byte> list = new List<byte>();
172                 list.Add(0);
173                 list.AddRange(buffer);
174                 //将泛型集合转换为数组
175                 byte[] newBuffer = list.ToArray();
176                 //获得用户选择的IP地址
177                 string ip = this.cmb_Socket.SelectedItem.ToString();
178                 dicSocket[ip].Send(newBuffer);
179             }
180             catch (Exception ex)
181             {
182                 MessageBox.Show("给客户端发送消息出错:"+ex.Message);
183             }
184             //socketSend.Send(buffer);
185         }
186 
187         /// <summary>
188         /// 选择要发送的文件
189         /// </summary>
190         /// <param name="sender"></param>
191         /// <param name="e"></param>
192         private void btn_Select_Click(object sender, EventArgs e)
193         {
194             OpenFileDialog dia = new OpenFileDialog();
195             //设置初始目录
196             dia.InitialDirectory = @"";
197             dia.Title = "请选择要发送的文件";
198             //过滤文件类型
199             dia.Filter = "所有文件|*.*";
200             dia.ShowDialog();
201             //将选择的文件的全路径赋值给文本框
202             this.txt_FilePath.Text = dia.FileName;
203         }
204 
205         /// <summary>
206         /// 发送文件
207         /// </summary>
208         /// <param name="sender"></param>
209         /// <param name="e"></param>
210         private void btn_SendFile_Click(object sender, EventArgs e)
211         {
212             List<byte> list = new List<byte>();
213             //获取要发送的文件的路径
214             string strPath = this.txt_FilePath.Text.Trim();
215             using (FileStream sw = new FileStream(strPath,FileMode.Open,FileAccess.Read))
216             {
217                 byte[] buffer = new byte[2048];
218                 int r = sw.Read(buffer, 0, buffer.Length);
219                 list.Add(1);
220                 list.AddRange(buffer);
221 
222                 byte[] newBuffer = list.ToArray();
223                 //发送
224                 //dicSocket[cmb_Socket.SelectedItem.ToString()].Send(newBuffer, 0, r+1, SocketFlags.None);
225                 btn_SendFile.Invoke(sendCallBack, newBuffer);
226 
227                 
228             }
229             
230         }
231 
232         private void SendFile(byte[] sendBuffer)
233         {
234 
235             try
236             {
237                 dicSocket[cmb_Socket.SelectedItem.ToString()].Send(sendBuffer, SocketFlags.None);
238             }
239             catch (Exception ex)
240             {
241                 MessageBox.Show("发送文件出错:"+ex.Message);
242             }
243         }
244 
245         private void btn_Shock_Click(object sender, EventArgs e)
246         {
247             byte[] buffer = new byte[1] { 2};
248             dicSocket[cmb_Socket.SelectedItem.ToString()].Send(buffer);
249         }
250 
251         /// <summary>
252         /// 停止监听
253         /// </summary>
254         /// <param name="sender"></param>
255         /// <param name="e"></param>
256         private void btn_StopListen_Click(object sender, EventArgs e)
257         {
258             socketWatch.Close();
259             socketSend.Close();
260             //终止线程
261             AcceptSocketThread.Abort();
262             threadReceive.Abort();
263         }
264     }
265 }

C#的socket

客户端界面

C#的socket代码实现如下:

C#的socket

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 using System.Net.Sockets;
 11 using System.Net;
 12 using System.Threading;
 13 using System.IO;
 14 
 15 namespace SocketClient
 16 {
 17     public partial class FrmClient : Form
 18     {
 19         public FrmClient()
 20         {
 21             InitializeComponent();
 22         }
 23 
 24         //定义回调
 25         private delegate void SetTextCallBack(string strValue);
 26         //声明
 27         private SetTextCallBack setCallBack;
 28 
 29         //定义接收服务端发送消息的回调
 30         private delegate void ReceiveMsgCallBack(string strMsg);
 31         //声明
 32         private ReceiveMsgCallBack receiveCallBack;
 33 
 34         //创建连接的Socket
 35         Socket socketSend;
 36         //创建接收客户端发送消息的线程
 37         Thread threadReceive;
 38 
 39         /// <summary>
 40         /// 连接
 41         /// </summary>
 42         /// <param name="sender"></param>
 43         /// <param name="e"></param>
 44         private void btn_Connect_Click(object sender, EventArgs e)
 45         {
 46             try
 47             {
 48                 socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 49                 IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
 50                 socketSend.Connect(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
 51                 //实例化回调
 52                 setCallBack = new SetTextCallBack(SetValue);
 53                 receiveCallBack = new ReceiveMsgCallBack(SetValue);
 54                 this.txt_Log.Invoke(setCallBack, "连接成功");
 55 
 56                 //开启一个新的线程不停的接收服务器发送消息的线程
 57                 threadReceive = new Thread(new ThreadStart(Receive));
 58                 //设置为后台线程
 59                 threadReceive.IsBackground = true;
 60                 threadReceive.Start();
 61             }
 62             catch (Exception ex)
 63             {
 64                 MessageBox.Show("连接服务端出错:" + ex.ToString());
 65             }
 66         }
 67 
 68         /// <summary>
 69         /// 接口服务器发送的消息
 70         /// </summary>
 71         private void Receive()
 72         {
 73             try
 74             {
 75                 while (true)
 76                 {
 77                     byte[] buffer = new byte[2048];
 78                     //实际接收到的字节数
 79                     int r = socketSend.Receive(buffer);
 80                     if (r == 0)
 81                     {
 82                         break;
 83                     }
 84                     else
 85                     {
 86                         //判断发送的数据的类型
 87                         if (buffer[0] == 0)//表示发送的是文字消息
 88                         {
 89                             string str = Encoding.Default.GetString(buffer, 1, r - 1);
 90                             this.txt_Log.Invoke(receiveCallBack, "接收远程服务器:" + socketSend.RemoteEndPoint + "发送的消息:" + str);
 91                         }
 92                         //表示发送的是文件
 93                         if (buffer[0] == 1)
 94                         {
 95                             SaveFileDialog sfd = new SaveFileDialog();
 96                             sfd.InitialDirectory = @"";
 97                             sfd.Title = "请选择要保存的文件";
 98                             sfd.Filter = "所有文件|*.*";
 99                             sfd.ShowDialog(this);
100 
101                             string strPath = sfd.FileName;
102                             using (FileStream fsWrite = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Write))
103                             {
104                                 fsWrite.Write(buffer, 1, r - 1);
105                             }
106 
107                             MessageBox.Show("保存文件成功");
108                         }
109                     }
110 
111 
112                 }
113             }
114             catch (Exception ex)
115             {
116                 MessageBox.Show("接收服务端发送的消息出错:" + ex.ToString());
117             }
118         }
119 
120 
121         private void SetValue(string strValue)
122         {
123             this.txt_Log.AppendText(strValue + "\r \n");
124         }
125 
126         /// <summary>
127         /// 客户端给服务器发送消息
128         /// </summary>
129         /// <param name="sender"></param>
130         /// <param name="e"></param>
131         private void btn_Send_Click(object sender, EventArgs e)
132         {
133             try
134             {
135                 string strMsg = this.txt_Msg.Text.Trim();
136                 byte[] buffer = new byte[2048];
137                 buffer = Encoding.Default.GetBytes(strMsg);
138                 int receive = socketSend.Send(buffer);
139             }
140             catch (Exception ex)
141             {
142                 MessageBox.Show("发送消息出错:" + ex.Message);
143             }
144         }
145 
146         private void FrmClient_Load(object sender, EventArgs e)
147         {
148             Control.CheckForIllegalCrossThreadCalls = false;
149         }
150 
151         /// <summary>
152         /// 断开连接
153         /// </summary>
154         /// <param name="sender"></param>
155         /// <param name="e"></param>
156         private void btn_CloseConnect_Click(object sender, EventArgs e)
157         {
158             //关闭socket
159             socketSend.Close();
160             //终止线程
161             threadReceive.Abort();
162         }
163     }
164 }