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

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

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

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

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

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

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

下面的是界面:



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

服务端代码:

[csharp]  view plain copy print ?
  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 + "\r\n");  
  141.         }  
  142.   
  143.         // 发送消息  
  144.         private void btnSend_Click(object sender, EventArgs e)  
  145.         {  
  146.             string strMsg = "服务器" + "\r\n" + "   -->" + txtMsgSend.Text.Trim() + "\r\n";  
  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 = "服务器" + "\r\n" + "   -->" + txtMsgSend.Text.Trim() + "\r\n";  
  173.             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;  
[csharp]  view plain copy print ?
  1.    
[csharp]  view plain copy print ?
  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 plain copy print ?
  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+"\r\n";  
  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 plain copy print ?
  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 + "\r\n");  
  107.         }  
  108.   
  109.          // 发送消息;  
  110.         private void btnSendMsg_Click(object sender, EventArgs e)  
  111.         {  
  112.             string strMsg = txtName.Text.Trim()+"\r\n"+"    -->"+ txtSendMsg.Text.Trim()+ "\r\n";  
  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 + "\r\n";  
  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. }  
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中,可以使用Socket来实现服务端客户端传输文件。 首先,在服务端创建一个Socket对象,并指定IPAddress和端口号。然后,使用Socket.Accept()方法等待客户端连接。一旦客户端连接成功,就可以通过Socket.SendFile()方法将文件发送给客户端。 以下是一个简单的示例代码: ```csharp // 服务端代码 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); int portNumber = 12345; Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(new IPEndPoint(ipAddress, portNumber)); serverSocket.Listen(1); Console.WriteLine("等待客户端连接..."); Socket clientSocket = serverSocket.Accept(); Console.WriteLine("客户端已连接"); string filePath = @"C:\test.txt"; SocketError errorCode; clientSocket.SendFile(filePath, null, null, TransmitFileOptions.UseDefaultWorkerThread, out errorCode); if (errorCode != SocketError.Success) { Console.WriteLine("发送失败,错误代码:{0}", errorCode); } else { Console.WriteLine("发送成功"); } // 关闭连接 clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); serverSocket.Close(); ``` 客户端代码如下: ```csharp // 客户端代码 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); int portNumber = 12345; Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.Connect(new IPEndPoint(ipAddress, portNumber)); Console.WriteLine("连接成功"); byte[] buffer = new byte[1024]; int bytesReceived = clientSocket.Receive(buffer); string message = Encoding.ASCII.GetString(buffer, 0, bytesReceived); Console.WriteLine("收到消息:{0}", message); // 关闭连接 clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); ``` 在上面的示例中,服务端文件发送给客户端客户端接收到文件后会显示收到消息。你可以根据自己的需求对代码进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值