• 基于C# Socket实现多人网络聊天室


    首先不多说,最终实现界面如下,可以通过点击启动服务,开启TCP服务器:

    开启TCP服务器之后,可以通过点击客户端,打开一个独立的TCP客户端,打开客户端之后,输入正确的IP地址和端口号,可以进行连接服务器,这里可以同时开启多个客户端:

    每个客户端连接成功后,服务器的列表中会多出一个EndPoint,连接成功后,服务器和客户端之间就可以自由通话了,可以发送消息,也可以发送文件。

    其实这就是QQ等即时通信工具的雏形,如果两个客户端之间需要通信,就通过服务器进行中转。

    由于服务器代码量较大,下面上传一下客户端的代码,仅供参考:

      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 MyTCPServer
     16 {
     17     delegate void FileSaveDelegate(byte[] bt,int length);
     18 
     19     public partial class FrmClient : Form
     20     {
     21         public FrmClient()
     22         {
     23             InitializeComponent();
     24 
     25             //委托对象绑定方法
     26             MyShowMsg += ShowMsg;
     27 
     28             MyFileSave += FileSave;
     29         }
     30 
     31         //运行标志位
     32         private bool IsRun = true;
     33 
     34         //创建连接服务器的Socket
     35         Socket sockClient = null;
     36 
     37         //创建接收服务器消息的线程
     38         Thread thrClient = null;
     39 
     40         //创建委托对象
     41         ShowMsgDelegate MyShowMsg;
     42 
     43         FileSaveDelegate MyFileSave;
     44 
     45         private void btnConnect_Click(object sender, EventArgs e)
     46         {
     47             //获取IP对象
     48             IPAddress address = IPAddress.Parse(this.txtIp.Text.Trim());
     49 
     50             //根据IP对象和端口号创建网络节点对象
     51             IPEndPoint endPoint = new IPEndPoint(address, int.Parse(this.txtPort.Text.Trim()));
     52 
     53             //创建负责连接的套接字,注意其中参数:[IPV4地址,字节流,TCP协议]
     54             sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     55 
     56             try
     57             {
     58                 Invoke(MyShowMsg, "与服务器连接中......");
     59                 sockClient.Connect(endPoint);
     60             }
     61             catch (Exception ex)
     62             {
     63                 MessageBox.Show("建立连接失败:" + ex.Message, "建立连接");
     64                 return;
     65             }
     66 
     67             Invoke(MyShowMsg, "与服务器连接成功!");
     68 
     69             thrClient = new Thread(ReceiveMsg);
     70             thrClient.IsBackground = true;
     71             thrClient.Start();
     72 
     73             this.btnConnect.Enabled = false;
     74         }
     75 
     76         private void FileSave(byte[] arrMsgRec, int length)
     77         {
     78             try
     79             {
     80                 SaveFileDialog sfd = new SaveFileDialog();
     81 
     82                 if (sfd.ShowDialog(this) == DialogResult.OK)
     83                 {
     84 
     85                     string fileSavePath = sfd.FileName;// 获得文件保存的路径;
     86                     // 创建文件流,然后根据路径创建文件;
     87                     using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
     88                     {
     89                         fs.Write(arrMsgRec, 1, length - 1);
     90                         Invoke(MyShowMsg, "文件保存成功:" + fileSavePath);
     91                     }
     92                 }
     93             }
     94             catch (Exception ex)
     95             {
     96                 MessageBox.Show(ex.Message);
     97             }
     98 
     99         }
    100 
    101         private void ReceiveMsg()
    102         {
    103            while(IsRun)
    104             {
    105                 // 定义一个2M的缓存区
    106                 byte[] arrMsgRec = new byte[1024 * 1024 * 2];
    107 
    108                 // 将接受到的数据存入到输入 arrMsgRec中
    109                 int length = -1;
    110                 try
    111                 {
    112                     length = sockClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
    113                 }
    114                 catch (SocketException)
    115                 {
    116                     return;
    117                 }
    118                 catch (Exception e)
    119                 {
    120                     Invoke(MyShowMsg, "连接断开:" + e.Message);
    121                     return;
    122                 }
    123                 if (arrMsgRec[0] == 0) // 表示接收到的是消息数据;
    124                 {
    125                     string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);// 将接受到的字节数据转化成字符串;
    126                     Invoke(MyShowMsg, strMsg);
    127                 }
    128                 if (arrMsgRec[0] == 1) // 表示接收到的是文件数据;
    129                 {
    130                     Invoke(MyFileSave, arrMsgRec, length);
    131                 }
    132             }
    133         }
    134 
    135         private void ShowMsg(string str)
    136         {
    137             txtMsg?.AppendText(str + Environment.NewLine);
    138         }
    139 
    140         private void btnSend_Click(object sender, EventArgs e)
    141         {
    142             string strMsg = txt_Name.Text.Trim() + Environment.NewLine + "    -->" + txtMsgSend.Text.Trim() + Environment.NewLine;
    143             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
    144             byte[] arrSendMsg = new byte[arrMsg.Length + 1];
    145             arrSendMsg[0] = 0; // 用来表示发送的是消息数据
    146             Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
    147             sockClient.Send(arrSendMsg); // 发送消息;
    148             Invoke(MyShowMsg, strMsg);
    149             txtMsgSend.Clear();
    150         }
    151 
    152         private void btnSendFile_Click(object sender, EventArgs e)
    153         {
    154             if (string.IsNullOrEmpty(txtSelectFile.Text))
    155             {
    156                 MessageBox.Show("请选择要发送的文件!!!");
    157             }
    158             else
    159             {
    160                 // 用文件流打开用户要发送的文件;
    161                 using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open))
    162                 {
    163                     //在发送文件以前先给好友发送这个文件的名字+扩展名,方便后面的保存操作;
    164                     string fileName = System.IO.Path.GetFileName(txtSelectFile.Text);
    165                     string fileExtension = System.IO.Path.GetExtension(txtSelectFile.Text);
    166                     string strMsg = "发送的文件为: " + fileName + Environment.NewLine;
    167                     byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
    168                     byte[] arrSendMsg = new byte[arrMsg.Length + 1];
    169                     arrSendMsg[0] = 0; // 用来表示发送的是消息数据
    170                     Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
    171                     sockClient.Send(arrSendMsg); // 发送消息;
    172 
    173                     byte[] arrFile = new byte[1024 * 1024 * 2];
    174                     int length = fs.Read(arrFile, 0, arrFile.Length);  // 将文件中的数据读到arrFile数组中;
    175                     byte[] arrFileSend = new byte[length + 1];
    176                     arrFileSend[0] = 1; // 用来表示发送的是文件数据;
    177                     Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);
    178                     // 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;
    179                     sockClient.Send(arrFileSend);// 发送数据到服务端;
    180                     txtSelectFile.Clear();
    181                 }
    182             }
    183         }
    184 
    185         private void btnSelectFile_Click(object sender, EventArgs e)
    186         {
    187             OpenFileDialog ofd = new OpenFileDialog();
    188             ofd.InitialDirectory = "D:\\";
    189             if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    190             {
    191                 txtSelectFile.Text = ofd.FileName;
    192             }
    193         }
    194 
    195         private void FrmClient_FormClosing(object sender, FormClosingEventArgs e)
    196         {
    197             IsRun  = false;
    198             sockClient?.Close();
    199         }
    200     }
    201 }

      如果大家还有什么不明白的地方,可以关注一下微信公众号:dotNet工控上位机

  • 相关阅读:
    python:xlrd模块
    psql:转:会引起全表扫描的10种sql语句
    Linux相关
    面试题
    Siege Web服务器性能压力测试工具
    Nginx+uWSGI+Supervisor配置
    SQLAlchemy
    Virtualenv创建虚拟环境
    算法
    Mac常用快捷键
  • 原文地址:https://www.cnblogs.com/xiketangedu/p/11459442.html
Copyright © 2020-2023  润新知