• C# TCP实现多个客户端与服务端 数据 与 文件的传输


    C#菜鸟做这个东东竟然花了快三天的时间了,真是菜,菜,菜~~~奋斗

    下面是我用C#写的 一个简单的TCP通信,主要的功能有:

    (1) 多个客户端与服务器间的数据交流

    (2)可以实现群发的功能

    (3)客户端与服务端可以进行文件的传输

    主要用到的知识: TCP里的 socket 、、、 多线程 Thread 、、、

    下面的是界面:

    下面分别是服务端和客户端的代码,如若借用,请标明出处~~~

    服务端代码:

    [csharp] view plaincopyprint?
     
    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.Windows.Forms;  
    9. using System.Net.Sockets;  
    10. using System.Net;  // IP,IPAddress, IPEndPoint,端口等;  
    11. using System.Threading;  
    12. using System.IO;  
    13.   
    14. namespace _11111  
    15. {  
    16.     public partial class frm_server : Form  
    17.     {  
    18.         public frm_server()  
    19.         {  
    20.             InitializeComponent();  
    21.             TextBox.CheckForIllegalCrossThreadCalls = false;  
    22.         }  
    23.   
    24.         Thread threadWatch = null; // 负责监听客户端连接请求的 线程;  
    25.         Socket socketWatch = null;  
    26.   
    27.         Dictionary<string, Socket> dict = new Dictionary<string, Socket>();  
    28.         Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();  
    29.   
    30.         private void btnBeginListen_Click(object sender, EventArgs e)  
    31.         {  
    32.             // 创建负责监听的套接字,注意其中的参数;  
    33.             socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
    34.             // 获得文本框中的IP对象;  
    35.             IPAddress address = IPAddress.Parse(txtIp.Text.Trim());  
    36.                 // 创建包含ip和端口号的网络节点对象;  
    37.                 IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));  
    38.                 try  
    39.                 {  
    40.                     // 将负责监听的套接字绑定到唯一的ip和端口上;  
    41.                     socketWatch.Bind(endPoint);  
    42.                 }  
    43.                 catch (SocketException se)  
    44.                 {  
    45.                     MessageBox.Show("异常:"+se.Message);  
    46.                     return;  
    47.                 }  
    48.                 // 设置监听队列的长度;  
    49.                 socketWatch.Listen(10);  
    50.                 // 创建负责监听的线程;  
    51.                 threadWatch = new Thread(WatchConnecting);  
    52.                 threadWatch.IsBackground = true;  
    53.                 threadWatch.Start();  
    54.                 ShowMsg("服务器启动监听成功!");  
    55.             //}  
    56.         }  
    57.   
    58.         /// <summary>  
    59.         /// 监听客户端请求的方法;  
    60.         /// </summary>  
    61.         void WatchConnecting()  
    62.         {  
    63.             while (true)  // 持续不断的监听客户端的连接请求;  
    64.             {  
    65.                 // 开始监听客户端连接请求,Accept方法会阻断当前的线程;  
    66.                 Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;  
    67.                 // 想列表控件中添加客户端的IP信息;  
    68.                 lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());  
    69.                 // 将与客户端连接的 套接字 对象添加到集合中;  
    70.                 dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);  
    71.                 ShowMsg("客户端连接成功!");  
    72.                 Thread thr = new Thread(RecMsg);  
    73.                 thr.IsBackground = true;  
    74.                 thr.Start(sokConnection);  
    75.                 dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);  //  将新建的线程 添加 到线程的集合中去。  
    76.             }  
    77.         }  
    78.   
    79.         void RecMsg(object sokConnectionparn)  
    80.         {  
    81.                 Socket sokClient = sokConnectionparn as Socket;  
    82.                 while (true)  
    83.                 {  
    84.                     // 定义一个2M的缓存区;  
    85.                     byte[] arrMsgRec = new byte[1024 * 1024 * 2];  
    86.                     // 将接受到的数据存入到输入  arrMsgRec中;  
    87.                     int length = -1;  
    88.                     try  
    89.                     {  
    90.                         length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;  
    91.                     }  
    92.                     catch (SocketException se)  
    93.                     {  
    94.                         ShowMsg("异常:" + se.Message);  
    95.                         // 从 通信套接字 集合中删除被中断连接的通信套接字;  
    96.                         dict.Remove(sokClient.RemoteEndPoint.ToString());  
    97.                         // 从通信线程集合中删除被中断连接的通信线程对象;  
    98.                         dictThread.Remove(sokClient.RemoteEndPoint.ToString());  
    99.                         // 从列表中移除被中断的连接IP  
    100.                         lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());  
    101.                         break;  
    102.                     }  
    103.                     catch (Exception e)  
    104.                     {  
    105.                         ShowMsg("异常:" + e.Message);  
    106.                         // 从 通信套接字 集合中删除被中断连接的通信套接字;  
    107.                         dict.Remove(sokClient.RemoteEndPoint.ToString());  
    108.                         // 从通信线程集合中删除被中断连接的通信线程对象;  
    109.                         dictThread.Remove(sokClient.RemoteEndPoint.ToString());  
    110.                         // 从列表中移除被中断的连接IP  
    111.                         lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());  
    112.                         break;  
    113.                     }  
    114.                     if (arrMsgRec[0] == 0)  // 表示接收到的是数据;  
    115.                     {  
    116.                         string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec,1, length-1);// 将接受到的字节数据转化成字符串;  
    117.                         ShowMsg(strMsg);  
    118.                     }  
    119.                     if (arrMsgRec[0] == 1) // 表示接收到的是文件;  
    120.                     {  
    121.                             SaveFileDialog sfd = new SaveFileDialog();  
    122.                              
    123.                             if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)  
    124.                             {// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】  
    125.                                  
    126.                                 string fileSavePath = sfd.FileName;// 获得文件保存的路径;  
    127.                                 // 创建文件流,然后根据路径创建文件;  
    128.                                 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))  
    129.                                 {  
    130.                                     fs.Write(arrMsgRec, 1, length - 1);  
    131.                                     ShowMsg("文件保存成功:" + fileSavePath);  
    132.                                 }  
    133.                             }  
    134.                         }  
    135.                 }       
    136.         }  
    137.   
    138.         void ShowMsg(string str)  
    139.         {  
    140.             txtMsg.AppendText(str + " ");  
    141.         }  
    142.   
    143.         // 发送消息  
    144.         private void btnSend_Click(object sender, EventArgs e)  
    145.         {  
    146.             string strMsg = "服务器" + " " + "   -->" + txtMsgSend.Text.Trim() + " ";  
    147.             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;  
    148.             byte[] arrSendMsg=new byte[arrMsg.Length+1];  
    149.             arrSendMsg[0] = 0; // 表示发送的是消息数据  
    150.             Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);  
    151.             string strKey = "";  
    152.             strKey = lbOnline.Text.Trim();  
    153.             if (string.IsNullOrEmpty(strKey))   // 判断是不是选择了发送的对象;  
    154.             {  
    155.                 MessageBox.Show("请选择你要发送的好友!!!");  
    156.             }  
    157.             else  
    158.             {  
    159.                 dict[strKey].Send(arrSendMsg);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;  
    160.                 ShowMsg(strMsg);  
    161.                 txtMsgSend.Clear();  
    162.             }  
    163.         }  
    164.   
    165.         /// <summary>  
    166.         /// 群发消息  
    167.         /// </summary>  
    168.         /// <param name="sender"></param>  
    169.         /// <param name="e">消息</param>  
    170.         private void btnSendToAll_Click(object sender, EventArgs e)  
    171.         {  
    172.             string strMsg = "服务器" + " " + "   -->" + txtMsgSend.Text.Trim() + " ";  
    173.             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;  
    [csharp] view plaincopyprint?
     
    1.    
    [csharp] view plaincopyprint?
     
    1.           <span style="font-size:14px;">  byte[] arrSendMsg = new byte[arrMsg.Length + 1]; // 上次写的时候把这一段给弄掉了,实在是抱歉哈~ 用来标识发送是数据而不是文件,如果没有这一段的客户端就接收不到消息了~~~  
    2.             arrSendMsg[0] = 0; // 表示发送的是消息数据  
    3.             Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);</span>  
    [csharp] view plaincopyprint?
     
    1.       
    2.             foreach (Socket s in dict.Values)  
    3.             {  
    4.                 s.Send(arrMsg);  
    5.             }  
    6.             ShowMsg(strMsg);  
    7.             txtMsgSend.Clear();  
    8.             ShowMsg(" 群发完毕~~~");  
    9.         }  
    10.   
    11.         // 选择要发送的文件  
    12.         private void btnSelectFile_Click_1(object sender, EventArgs e)  
    13.         {  
    14.             OpenFileDialog ofd = new OpenFileDialog();  
    15.             ofd.InitialDirectory = "D:\";  
    16.             if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)  
    17.             {  
    18.                 txtSelectFile.Text = ofd.FileName;  
    19.             }  
    20.         }  
    21.   
    22.         // 文件的发送  
    23.         private void btnSendFile_Click_1(object sender, EventArgs e)  
    24.         {  
    25.             if (string.IsNullOrEmpty(txtSelectFile.Text))  
    26.             {  
    27.                 MessageBox.Show("请选择你要发送的文件!!!");  
    28.             }  
    29.             else  
    30.             {  
    31.                 // 用文件流打开用户要发送的文件;  
    32.                 using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open))  
    33.                 {  
    34.                     string fileName=System.IO.Path.GetFileName(txtSelectFile.Text);  
    35.                     string fileExtension=System.IO.Path.GetExtension(txtSelectFile.Text);  
    36.                     string strMsg = "我给你发送的文件为: "+fileName+fileExtension+" ";  
    37.                     byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;  
    38.                     byte[] arrSendMsg = new byte[arrMsg.Length + 1];  
    39.                     arrSendMsg[0] = 0; // 表示发送的是消息数据  
    40.                     Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);  
    41.                     bool fff = true;  
    42.                     string strKey = "";  
    43.                     strKey = lbOnline.Text.Trim();  
    44.                     if (string.IsNullOrEmpty(strKey))   // 判断是不是选择了发送的对象;  
    45.                     {  
    46.                         MessageBox.Show("请选择你要发送的好友!!!");  
    47.                     }  
    48.                     else  
    49.                     {  
    50.                     dict[strKey].Send(arrSendMsg);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;  
    51.                     byte[] arrFile = new byte[1024 * 1024 * 2];  
    52.                     int length = fs.Read(arrFile, 0, arrFile.Length);  // 将文件中的数据读到arrFile数组中;  
    53.                     byte[] arrFileSend = new byte[length + 1];  
    54.                     arrFileSend[0] = 1; // 用来表示发送的是文件数据;  
    55.                     Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);  
    56.                     // 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;  
    57.                     //  sockClient.Send(arrFileSend);// 发送数据到服务端;  
    58.                     dict[strKey].Send(arrFileSend);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;  
    59.                        txtSelectFile.Clear();   
    60.                     }  
    61.                 }  
    62.             }  
    63.             txtSelectFile.Clear();  
    64.         }  
    65.   
    66.     }  
    67. }  


    客户端代码:

    [csharp] view plaincopyprint?
     
      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.Windows.Forms;  
      9.   
      10. using System.Net;  
      11. using System.Net.Sockets;  
      12. using System.Threading;  
      13. using System.IO;  
      14.   
      15. namespace _2222222  
      16. {  
      17.     public partial class frmClient : Form  
      18.     {  
      19.         public frmClient()  
      20.         {  
      21.             InitializeComponent();  
      22.             TextBox.CheckForIllegalCrossThreadCalls = false;  
      23.         }  
      24.   
      25.         Thread threadClient = null; // 创建用于接收服务端消息的 线程;  
      26.         Socket sockClient = null;  
      27.         private void btnConnect_Click(object sender, EventArgs e)  
      28.         {  
      29.             IPAddress ip = IPAddress.Parse(txtIp.Text.Trim());  
      30.             IPEndPoint endPoint=new IPEndPoint (ip,int.Parse(txtPort.Text.Trim()));  
      31.             sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
      32.             try  
      33.             {  
      34.                 ShowMsg("与服务器连接中……");  
      35.                 sockClient.Connect(endPoint);  
      36.                   
      37.             }  
      38.             catch (SocketException se)  
      39.             {  
      40.                 MessageBox.Show(se.Message);  
      41.                 return;  
      42.                 //this.Close();  
      43.             }  
      44.             ShowMsg("与服务器连接成功!!!");  
      45.             threadClient = new Thread(RecMsg);  
      46.             threadClient.IsBackground = true;  
      47.             threadClient.Start();  
      48.   
      49.         }  
      50.   
      51.         void RecMsg()  
      52.         {  
      53.             while (true)  
      54.             {  
      55.                 // 定义一个2M的缓存区;  
      56.                 byte[] arrMsgRec = new byte[1024 * 1024 * 2];  
      57.                 // 将接受到的数据存入到输入  arrMsgRec中;  
      58.                 int length = -1;  
      59.                 try  
      60.                 {  
      61.                     length = sockClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;  
      62.                 }  
      63.                 catch (SocketException se)  
      64.                 {  
      65.                     ShowMsg("异常;" + se.Message);  
      66.                     return;  
      67.                 }  
      68.                 catch (Exception e)  
      69.                 {  
      70.                     ShowMsg("异常:"+e.Message);  
      71.                     return;  
      72.                 }  
      73.                 if (arrMsgRec[0] == 0) // 表示接收到的是消息数据;  
      74.                 {  
      75.                     string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length-1);// 将接受到的字节数据转化成字符串;  
      76.                     ShowMsg(strMsg);  
      77.                 }  
      78.                 if (arrMsgRec[0] == 1) // 表示接收到的是文件数据;  
      79.                 {  
      80.                      
      81.                     try  
      82.                     {  
      83.                         SaveFileDialog sfd = new SaveFileDialog();  
      84.   
      85.                         if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)  
      86.                         {// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】  
      87.   
      88.                             string fileSavePath = sfd.FileName;// 获得文件保存的路径;  
      89.                             // 创建文件流,然后根据路径创建文件;  
      90.                             using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))  
      91.                             {  
      92.                                 fs.Write(arrMsgRec, 1, length - 1);  
      93.                                 ShowMsg("文件保存成功:" + fileSavePath);  
      94.                             }  
      95.                         }  
      96.                     }  
      97.                     catch (Exception aaa)  
      98.                     {  
      99.                         MessageBox.Show(aaa.Message);  
      100.                     }  
      101.                 }  
      102.             }  
      103.         }  
      104.         void ShowMsg(string str)  
      105.         {  
      106.             txtMsg.AppendText(str + " ");  
      107.         }  
      108.   
      109.          // 发送消息;  
      110.         private void btnSendMsg_Click(object sender, EventArgs e)  
      111.         {  
      112.             string strMsg = txtName.Text.Trim()+" "+"    -->"+ txtSendMsg.Text.Trim()+ " ";  
      113.             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);  
      114.             byte[] arrSendMsg = new byte[arrMsg.Length + 1];  
      115.             arrSendMsg[0] = 0; // 用来表示发送的是消息数据  
      116.             Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);  
      117.             sockClient.Send(arrSendMsg); // 发送消息;  
      118.             ShowMsg(strMsg);  
      119.             txtSendMsg.Clear();  
      120.         }  
      121.   
      122.        // 选择要发送的文件;  
      123.         private void btnSelectFile_Click(object sender, EventArgs e)  
      124.         {  
      125.             OpenFileDialog ofd = new OpenFileDialog();  
      126.             ofd.InitialDirectory = "D:\";  
      127.             if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)  
      128.             {  
      129.                 txtSelectFile.Text = ofd.FileName;  
      130.             }  
      131.         }  
      132.   
      133.         //向服务器端发送文件  
      134.         private void btnSendFile_Click(object sender, EventArgs e)  
      135.         {  
      136.             if (string.IsNullOrEmpty(txtSelectFile.Text))  
      137.             {  
      138.                 MessageBox.Show("请选择要发送的文件!!!");  
      139.             }  
      140.             else  
      141.             {  
      142.                 // 用文件流打开用户要发送的文件;  
      143.                 using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open))  
      144.                 {  
      145.                     //在发送文件以前先给好友发送这个文件的名字+扩展名,方便后面的保存操作;  
      146.                     string fileName = System.IO.Path.GetFileName(txtSelectFile.Text);  
      147.                     string fileExtension = System.IO.Path.GetExtension(txtSelectFile.Text);  
      148.                     string strMsg = "我给你发送的文件为: " + fileName + " ";  
      149.                     byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);  
      150.                     byte[] arrSendMsg = new byte[arrMsg.Length + 1];  
      151.                     arrSendMsg[0] = 0; // 用来表示发送的是消息数据  
      152.                     Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);  
      153.                     sockClient.Send(arrSendMsg); // 发送消息;  
      154.                      
      155.                     byte[] arrFile = new byte[1024 * 1024 * 2];  
      156.                     int length = fs.Read(arrFile, 0, arrFile.Length);  // 将文件中的数据读到arrFile数组中;  
      157.                     byte[] arrFileSend = new byte[length + 1];  
      158.                     arrFileSend[0] = 1; // 用来表示发送的是文件数据;  
      159.                     Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);  
      160.                     // 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;  
      161.                     sockClient.Send(arrFileSend);// 发送数据到服务端;  
      162.                     txtSelectFile.Clear();   
      163.                 }  
      164.             }           
      165.         }  
      166.     }  
      167. }  
        1. 转自http://blog.csdn.net/chwei_cson/article/details/7737766
  • 相关阅读:
    提示35. 怎样实现OfTypeOnly<TEntity>()这样的写法
    (翻译)Entity Framework技巧系列之十
    Entity Framework教程(第二版)
    实战 ASP.NET Web API
    Apache,PHP,MySQL的安装,配置
    Apache配置虚拟目录和多主机头
    web.config配置详细说明
    百度UEditor编辑器使用教程与使用方法
    若要调试此模块,请将其项目生成配置更改为“调试”模式。若要取消显示此消息,请禁用“启动时若没有用户代码则发出警告”调试器选项
    jquery筛选器
  • 原文地址:https://www.cnblogs.com/catWang/p/4081349.html
Copyright © 2020-2023  润新知