Socket连接

  Socket使用TCP协议,TCP是一种面向连接的、可靠的,基于字节流的传输层通信协议。为两台主机提供高可靠性的数据通信服务。它可以将源主机的数据无差错地传输到目标主机。当有数据要发送时,对应用进程送来的数据进行分片,以适合于在网络层中传输;当接收到网络层传来的分组时,它要对收到的分组进行确认,还要对丢失的分组设置超时重发等。为此TCP需要增加额外的许多开销,以便在数据传输过程中进行一些必要的控制,确保数据的可靠传输。因此,TCP传输的效率比较低。一旦通信双方建立了TCP连接,连接中的任何一方都能向对方发送数据和接收对方发来的数据。TCP协议负责把用户数据(字节流)按一定的格式和长度组成多个数据报进行发送,并在接收到数据报之后按分解顺序重新组装和恢复用户数据。利用TCP传输数据时,数据是以字节流的形式进行传输的。

  TCP是面向连接的协议,TCP协议通过三个报文段完成类似电话呼叫的连接建立过程,这个过程称为三次握手

  第一次握手:建立连接时,客户端发送SYN包(SEQ=x)到服务器,并进入SYN_SEND状态,等待服务器确认。

  第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=x+1),同时自己也发送一个SYN包(SEQ=y),即SYN+ACK包,此时服务器进入  SYN_RECV状态。

  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=y+1),此包发送完毕,客户端和服务器进入Established状态,完成三次握手。

  建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由TCP的半关闭造成的。

  TCP是以全双工方式运输,一对一通信。

  Socket的基本通信:

  服务器端:

  1、创建用于监听的Socket对象,创建用于通信的Socket对象
  2、使用监听的Socket对象的Bind方法与IP和端口进行绑定,再通过Socket对象的Listen方法进行监听
  3、将通信的Socket对象使用Accept方法创建新连接
  4、通过Socket对象的Send方法和Recieve方法进行通讯
  5、通信结束后关闭Socket

  客户端:

  1、创建用于通信的Socket对象
  2、Socket对象使用Connect方法创建一个和IP与端口的连接
  3、通过该Socket对象的Send方法和Recieve方法进行通讯
  4、通信结束后关闭Socket

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

服务器端示图

客户端示图

 

 参考原文:点这里

posted @   zengxw1113  阅读(155)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 快收藏!一个技巧从此不再搞混缓存穿透和缓存击穿
· Blazor Hybrid适配到HarmonyOS系统
· 支付宝 IoT 设备入门宝典(下)设备经营篇
· 万字调研——AI生成内容检测
· 解决跨域问题的这6种方案,真香!
点击右上角即可分享
微信分享提示