开发文章

C#使用socket实现网络客户端与服务端通信

注意:此例子的目的只是为了说明用套接字写程序的大概思路,而不是实际项目中的使用程序。在这个例子中,实际上还有很多问题没有解决,如消息边界问题、端口号是否被占用、消息命令的解析粘包、断包问题等。。

源码下载地址

http://download.csdn.net/detail/pplsunny/9663876

TCP/IP:Transmission Control Protocol/Internet Protocol,传输控制协议/因特网互联协议,又名网络通讯协议。简单来说:TCP控制传输数据,负责发现传输的问题,一旦有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地,而IP是负责给因特网中的每一台电脑定义一个地址,以便传输。从协议分层模型方面来讲:TCP/IP由:网络接口层(链路层)、网络层、传输层、应用层。它和OSI的七层结构以及对于协议族不同,下图简单表示:

OSI的七层结构以及对于协议族.jpg

现阶段socket通信使用TCP、UDP协议,相对应UDP来说,TCP则是比较安全稳定的协议了。本文只涉及到TCP协议来说socket通信。首先讲述TCP/IP的三次握手,在握手基础上延伸socket通信的基本过程。

下面介绍对于应届生毕业面试来说是非常熟悉的,同时也是最臭名昭著的三次握手:

1 客户端发送syn报文到服务器端,并置发送序号为x。

2 服务器端接收到客户端发送的请求报文,然后向客户端发送syn报文,并且发送确认序号x+1,并置发送序号为y。

3 客户端受到服务器发送确认报文后,发送确认信号y+1,并置发送序号为z。至此客户端和服务器端建立连接。

TCP—IP的三次握手.jpg

在此基础上,socket连接过程:

服务器监听:服务器端socket并不定位具体的客户端socket,而是处于等待监听状态,实时监控网络状态。

客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。为此,clientSocket必须知道serverSocket的地址和端口号,进行扫描发出连接请求。

连接确认:当服务器socket监听到或者是受到客户端socket的连接请求时,服务器就响应客户端的请求,建议一个新的socket,把服务器socket发送给客户端,一旦客户端确认连接,则连接建立。

注:在连接确认阶段:服务器socket即使在和一个客户端socket建立连接后,还在处于监听状态,仍然可以接收到其他客户端的连接请求,这也是一对多产生的原因。

下图简单说明连接过程:

连接过程.jpg

socket连接原理知道了,此处编写最基本最简单的socket通信:

服务器端

服务器端.jpg

复制内容到剪贴板
  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;    
  11. using System.Threading.Tasks;    
  12. using System.Windows.Forms;    
  13.     
  14. namespace WFSocket    
  15. {    
  16.     public partial class Form1 : Form    
  17.     {    
  18.         /// <summary>    
  19.         /// 用来存放连接服务的客户端的IP地址和端口号,对应的Socket    
  20.         /// </summary>    
  21.         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();    
  22.     
  23.         public Form1()    
  24.         {    
  25.             InitializeComponent();    
  26.         }    
  27.     
  28.         /// <summary>    
  29.         /// 初期化    
  30.         /// </summary>    
  31.         /// <param name="sender"></param>    
  32.         /// <param name="e"></param>    
  33.         private void Form1_Load(object sender, EventArgs e)    
  34.         {    
  35.             //不检测跨线程之间的空间调用    
  36.             Control.CheckForIllegalCrossThreadCalls = false;    
  37.         }    
  38.     
  39.         /// <summary>    
  40.         /// 开始监听按钮    
  41.         /// </summary>    
  42.         /// <param name="sender"></param>    
  43.         /// <param name="e"></param>    
  44.         private void btnListen_Click(object sender, EventArgs e)    
  45.         {    
  46.             try    
  47.             {    
  48.                 //当点击开始监听的时候 在服务器端创建一个负责监IP地址跟端口号的Socket    
  49.                 Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);    
  50.     
  51.                 //获取IP    
  52.                 //IPAddress ip = IPAddress.Any;    
  53.                 //服务器IP地址     
  54.                 //********************************    
  55.                 //要添加IP合法性检测    
  56.                 //TODO    
  57.                 //********************************    
  58.     
  59.                 IPAddress ip = IPAddress.Parse(ipAddress.Text.Trim());    
  60.     
  61.                 //创建端口号    
  62.                 IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(serverPort.Text.Trim()));    
  63.     
  64.                 //监听    
  65.                 socketWatch.Bind(port);    
  66.     
  67.                 ShowMsg("监听成功");    
  68.     
  69.                 //********************************    
  70.                 //监听成功后按钮要非活性,不可再点击    
  71.                 //TODO    
  72.                 //********************************    
  73.     
  74.                 //设定最多10个排队连接请求     
  75.                 socketWatch.Listen(10);    
  76.     
  77.                 //新建线程,去接收客户端发来的信息    
  78.                 Thread td = new Thread(AcceptClientMgs);    
  79.                 td.IsBackground = true;    
  80.                 td.Start(socketWatch);    
  81.             }    
  82.             catch (Exception)    
  83.             {                  
  84.                 throw;    
  85.             }    
  86.         }    
  87.     
  88.         /// <summary>    
  89.         /// 接收客户端发送的信息    
  90.         /// </summary>    
  91.         /// <param name="o"></param>    
  92.         private void AcceptClientMgs(object o)    
  93.         {    
  94.             try    
  95.             {    
  96.                 Socket socketWatc = (Socket)o;    
  97.                 while (true)    
  98.                 {    
  99.                     ////负责跟客户端通信的Socket    
  100.                     Socket socketSend = socketWatc.Accept();    
  101.     
  102.                     //将远程连接的客户端的IP地址和Socket存入集合中    
  103.                     dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);    
  104.     
  105.                     ShowMsg(socketSend.RemoteEndPoint.ToString() + ": 连接成功");    
  106.     
  107.                     //新建线程循环接收客户端发来的信息    
  108.                     Thread td = new Thread(Recive);    
  109.                     td.IsBackground = true;    
  110.                     td.Start(socketSend);    
  111.                 }    
  112.             }    
  113.             catch { }    
  114.     
  115.         }    
  116.     
  117.         /// <summary>    
  118.         /// 接收客户端发来的数据,并显示出来    
  119.         /// </summary>    
  120.         private void Recive(object o)    
  121.         {    
  122.             Socket socketSend = (Socket)o;    
  123.             try    
  124.             {    
  125.                 while (true)    
  126.                 {    
  127.                     //客户端连接成功后,服务器应该接受客户端发来的消息    
  128.     
  129.                     if (socketSend == null)    
  130.                     {    
  131.                         ShowMsg("客户端没有发送信息。");    
  132.                         continue;    
  133.                     }    
  134.     
  135.                     byte[] buffer = new byte[1024 * 1024 * 2];    
  136.                     //实际接受到的有效字节数    
  137.                     int r = socketSend.Receive(buffer);    
  138.                     //如果客户端关闭,发送的数据就为空,然后就跳出循环    
  139.                     if (r == 0)    
  140.                     {    
  141.                         break;    
  142.                     }    
  143.     
  144.                     //接收客户端信息    
  145.                     string strMsg = Encoding.UTF8.GetString(buffer, 0, r);    
  146.     
  147.                     byte[] acceptbuffer = Encoding.UTF8.GetBytes("服务器端接收成功");    
  148.     
  149.                     //将字节数组传递给客户端    
  150.                     socketSend.Send(acceptbuffer);    
  151.     
  152.                     ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);    
  153.                 }    
  154.             }    
  155.             catch { }    
  156.         }    
  157.     
  158.         /// <summary>    
  159.         /// 显示信息    
  160.         /// </summary>    
  161.         /// <param name="message"></param>    
  162.         private void ShowMsg(string message)    
  163.         {    
  164.             serverMessage.AppendText(message + "\r\n");    
  165.         }    
  166.            
  167.     }    
  168. }    

客户端

客户端.jpg

复制内容到剪贴板
  1. using Newtonsoft.Json;    
  2. using System;    
  3. using System.Collections.Generic;    
  4. using System.ComponentModel;    
  5. using System.Data;    
  6. using System.Drawing;    
  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 WFClient    
  16. {    
  17.     public partial class Form1 : Form    
  18.     {    
  19.         /// <summary>    
  20.         /// 用来存放连接服务的IP地址和端口号,对应的Socket (这个为了以后的扩展用,现在暂时没用)    
  21.         /// </summary>    
  22.         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();    
  23.     
  24.         /// <summary>    
  25.         /// 负责通信的Socket    
  26.         /// </summary>    
  27.         Socket socketSend;        
  28.     
  29.         public Form1()    
  30.         {    
  31.             InitializeComponent();    
  32.         }    
  33.     
  34.         private void Form1_Load(object sender, EventArgs e)    
  35.         {    
  36.             //不检测跨线程之间的空间调用    
  37.             Control.CheckForIllegalCrossThreadCalls = false;    
  38.         }    
  39.     
  40.         /// <summary>    
  41.         /// 建立连接    
  42.         /// </summary>    
  43.         /// <param name="sender"></param>    
  44.         /// <param name="e"></param>    
  45.         private void connectionSer_Click(object sender, EventArgs e)    
  46.         {    
  47.             try    
  48.             {    
  49.                 //创建负责通信的Socket    
  50.                 socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);    
  51.     
  52.                 //获取服务端的IP    
  53.                 IPAddress ip = IPAddress.Parse(sipAddress.Text.Trim());    
  54.     
  55.                 //获取服务端的端口号    
  56.                 IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(serverPort.Text.Trim()));    
  57.     
  58.                 //获得要连接的远程服务器应用程序的IP地址和端口号    
  59.                 socketSend.Connect(port);    
  60.                     
  61.                 //新建线程,去接收客户端发来的信息    
  62.                 Thread td = new Thread(AcceptMgs);    
  63.                 td.IsBackground = true;    
  64.                 td.Start();    
  65.             }    
  66.             catch { }    
  67.         }    
  68.     
  69.         /// <summary>    
  70.         /// 发送数据    
  71.         /// </summary>    
  72.         /// <param name="sender"></param>    
  73.         /// <param name="e"></param>    
  74.         private void btnSend_Click(object sender, EventArgs e)    
  75.         {    
  76.             try    
  77.             {    
  78.                 PrintData tempData = new PrintData();    
  79.                 tempData.TemplatePath = @"C:\templates";    
  80.                 tempData.TemplateName = "lablete.lbx";    
  81.                     
  82.                      Dictionary<stringstring> printData = new Dictionary<stringstring>();    
  83.                      printData.Add("objName", sendMessage.Text);    
  84.                 printData.Add("objNum""test001");    
  85.                 tempData.PrintDataList = printData;    
  86.     
  87.                 //实体序列化和反序列化      
  88.                 string json1 = SerializeObject(tempData);    
  89.     
  90.                 byte[] buffer = Encoding.UTF8.GetBytes(json1);    
  91.                      
  92.                 //将字节数组传递给客户端    
  93.                 socketSend.Send(buffer);    
  94.                 sendMessage.Text = "";    
  95.             }    
  96.             catch { }       
  97.         }    
  98.     
  99.         /// <summary>    
  100.         /// 客户端接收服务器端返回的数据    
  101.         /// </summary>    
  102.         private void AcceptMgs()    
  103.         {    
  104.             try    
  105.             {                
  106.                 while (true)    
  107.                 {    
  108.                     byte[] buffer = new byte[1024 * 1024];    
  109.                     int r = socketSend.Receive(buffer);    
  110.                     if (r == 0)    
  111.                     {    
  112.                         break;    
  113.                     }    
  114.                         
  115.                     //信息显示    
  116.                     string strMsg = Encoding.UTF8.GetString(buffer, 0, r);    
  117.                     ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);                  
  118.                 }    
  119.             }    
  120.             catch { }    
  121.         }    
  122.     
  123.         /// <summary>    
  124.         /// 显示信息    
  125.         /// </summary>    
  126.         /// <param name="message"></param>    
  127.         private void ShowMsg(string message)    
  128.         {    
  129.             resultMsg.AppendText(message + "\r\n");    
  130.         }    
  131.     
  132.         /// <summary>      
  133.         /// 将对象序列化为JSON格式      
  134.         /// </summary>      
  135.         /// <param name="o">对象</param>      
  136.         /// <returns>json字符串</returns>      
  137.         public string SerializeObject(object o)    
  138.         {    
  139.             string json = JsonConvert.SerializeObject(o);    
  140.             return json;    
  141.         }      
  142.     
  143.     }    
  144. }    

C#使用socket实现网络客户端与服务端通信.jpg

感谢 一羽清宁 支持 磐实编程网 原文地址:
blog.csdn.net/pplcheer/article/details/52927437

文章信息

发布时间:2016-10-26

作者:一羽清宁

发布者:aquwcw

浏览次数: