C#使用Socket实现服务器与多个客户端通信(简单的聊天系统)

 更新时间:2020年6月25日 10:35  点击:1585

扩展:
由于server端是存储了所有server与client的连接对象,因此我们是可以基于此demo的基础上实现聊天系统:

* 每当一个与用户发言时,是由server接收到的某个用户的发言信息的,此时服务器端可以通过循环发送该用户发送的信息给每个已经连接连接的用户(排除发送者)。

Server端代码:

class Program
{
  //创建一个和客户端通信的套接字
  static Socket SocketWatch = null;
  //定义一个集合,存储客户端信息
  static Dictionary<string, Socket> ClientConnectionItems = new Dictionary<string, Socket> { };
 
  static void Main(string[] args)
  {
    //端口号(用来监听的)
    int port = 6000;
 
    //string host = "127.0.0.1";
    //IPAddress ip = IPAddress.Parse(host);
    IPAddress ip = IPAddress.Any;
 
    //将IP地址和端口号绑定到网络节点point上 
    IPEndPoint ipe = new IPEndPoint(ip, port);
 
    //定义一个套接字用于监听客户端发来的消息,包含三个参数(IP4寻址协议,流式连接,Tcp协议) 
    SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //监听绑定的网络节点 
    SocketWatch.Bind(ipe);
    //将套接字的监听队列长度限制为20 
    SocketWatch.Listen(20);
 
 
    //负责监听客户端的线程:创建一个监听线程 
    Thread threadwatch = new Thread(WatchConnecting);
    //将窗体线程设置为与后台同步,随着主线程结束而结束 
    threadwatch.IsBackground = true;
    //启动线程   
    threadwatch.Start();
 
    Console.WriteLine("开启监听......");
    Console.WriteLine("点击输入任意数据回车退出程序......");
    Console.ReadKey();
 
    SocketWatch.Close();
 
    //Socket serverSocket = null;
 
    //int i=1;
    //while (true)
    //{
    //  //receive message
    //  serverSocket = SocketWatch.Accept();
    //  Console.WriteLine("连接已经建立!");
    //  string recStr = "";
    //  byte[] recByte = new byte[4096];
    //  int bytes = serverSocket.Receive(recByte, recByte.Length, 0);
    //  //recStr += Encoding.ASCII.GetString(recByte, 0, bytes);
    //  recStr += Encoding.GetEncoding("utf-8").GetString(recByte, 0, bytes);
 
    //  //send message
    //  Console.WriteLine(recStr);
 
    //  Console.Write("请输入内容:");
    //  string sendStr = Console.ReadLine();
 
    //  //byte[] sendByte = Encoding.ASCII.GetBytes(sendStr);
    //  byte[] sendByte = Encoding.GetEncoding("utf-8").GetBytes(sendStr);
 
    //  //Thread.Sleep(4000);
 
    //  serverSocket.Send(sendByte, sendByte.Length, 0);
    //  serverSocket.Close();
    //  if (i >= 100)
    //  {
    //    break;
    //  }
    //  i++;
    //}
      
    //sSocket.Close();
    //Console.WriteLine("连接关闭!");
 
 
    //Console.ReadLine();
  }
 
  //监听客户端发来的请求 
  static void WatchConnecting()
  {
    Socket connection = null;
 
    //持续不断监听客户端发来的请求   
    while (true)
    {
      try
      {
        connection = SocketWatch.Accept();
      }
      catch (Exception ex)
      {
        //提示套接字监听异常   
        Console.WriteLine(ex.Message);
        break;
      }
 
      //客户端网络结点号 
      string remoteEndPoint = connection.RemoteEndPoint.ToString();
      //添加客户端信息 
      ClientConnectionItems.Add(remoteEndPoint, connection);
      //显示与客户端连接情况
      Console.WriteLine("\r\n[客户端\"" + remoteEndPoint + "\"建立连接成功! 客户端数量:" + ClientConnectionItems .Count+ "]");
 
      //获取客户端的IP和端口号 
      IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
      int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;
 
      //让客户显示"连接成功的"的信息 
      string sendmsg = "[" + "本地IP:" + clientIP + " 本地端口:" + clientPort.ToString() + " 连接服务端成功!]";
      byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);
      connection.Send(arrSendMsg);
 
      //创建一个通信线程   
      Thread thread = new Thread(recv);
      //设置为后台线程,随着主线程退出而退出 
      thread.IsBackground = true;
      //启动线程   
      thread.Start(connection);
    }
  }
 
  /// <summary>
  /// 接收客户端发来的信息,客户端套接字对象
  /// </summary>
  /// <param name="socketclientpara"></param>  
  static void recv(object socketclientpara)
  {
    Socket socketServer = socketclientpara as Socket;
 
    while (true)
    {
      //创建一个内存缓冲区,其大小为1024*1024字节 即1M   
      byte[] arrServerRecMsg = new byte[1024 * 1024];
      //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度  
      try
      {
        int length = socketServer.Receive(arrServerRecMsg);
 
        //将机器接受到的字节数组转换为人可以读懂的字符串   
        string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
 
        //将发送的字符串信息附加到文本框txtMsg上   
        Console.WriteLine("\r\n[客户端:" + socketServer.RemoteEndPoint + " 时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")+ "]\r\n" + strSRecMsg);
 
        //Thread.Sleep(3000);
        //socketServer.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:"+strSRecMsg));
        //发送客户端数据
        if (ClientConnectionItems.Count > 0)
        {
          foreach (var socketTemp in ClientConnectionItems)
          {
            socketTemp.Value.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:" + strSRecMsg));
          }
        }
      }
      catch (Exception)
      {
        ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
        //提示套接字监听异常 
        Console.WriteLine("\r\n[客户端\"" + socketServer.RemoteEndPoint + "\"已经中断连接! 客户端数量:" + ClientConnectionItems.Count+"]");
        //关闭之前accept出来的和客户端进行通信的套接字 
        socketServer.Close();
        break;
      }
    }
  }
}

Client端代码:

class Program
{
  //创建1个客户端套接字和1个负责监听服务端请求的线程 
  static Thread ThreadClient = null;
  static Socket SocketClient = null;
 
  static void Main(string[] args)
  {
    try
    {
      int port = 6000;
      string host = "127.0.0.1";//服务器端ip地址
 
      IPAddress ip = IPAddress.Parse(host);
      IPEndPoint ipe = new IPEndPoint(ip, port);
 
      //定义一个套接字监听 
      SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
      try
      {
        //客户端套接字连接到网络节点上,用的是Connect 
        SocketClient.Connect(ipe);
      }
      catch (Exception)
      {
        Console.WriteLine("连接失败!\r\n");
        Console.ReadLine();
        return;
      }
 
      ThreadClient = new Thread(Recv);
      ThreadClient.IsBackground = true;
      ThreadClient.Start();
 
      Thread.Sleep(1000);
      Console.WriteLine("请输入内容<按Enter键发送>:\r\n");
      while(true)
      {
        string sendStr = Console.ReadLine();
        ClientSendMsg(sendStr);
      }
 
      //int i = 1;
      //while (true)
      //{
      //  Console.Write("请输入内容:");
      //  string sendStr = Console.ReadLine();
 
      //  Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      //  clientSocket.Connect(ipe);
      //  //send message
      //  //byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);
      //  byte[] sendBytes = Encoding.GetEncoding("utf-8").GetBytes(sendStr);
 
      //  //Thread.Sleep(4000);
 
      //  clientSocket.Send(sendBytes);
 
      //  //receive message
      //  string recStr = ""; 
      //  byte[] recBytes = new byte[4096];
      //  int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
      //  //recStr += Encoding.ASCII.GetString(recBytes, 0, bytes);
      //  recStr += Encoding.GetEncoding("utf-8").GetString(recBytes, 0, bytes);
      //  Console.WriteLine(recStr);
 
      //  clientSocket.Close();
      //  if (i >= 100)
      //  {
      //    break;
      //  }
      //  i++;
      //}
        
      //Console.ReadLine();
      //return;
 
      //string result = String.Empty;
 
    }
    catch (Exception ex) 
    {
      Console.WriteLine(ex.Message);
      Console.ReadLine();
    }
  }
 
  //接收服务端发来信息的方法  
  public static void Recv()
  {
      int x = 0;
    //持续监听服务端发来的消息 
    while (true)
    {
      try
      {
        //定义一个1M的内存缓冲区,用于临时性存储接收到的消息 
        byte[] arrRecvmsg = new byte[1024 * 1024];
 
        //将客户端套接字接收到的数据存入内存缓冲区,并获取长度 
        int length = SocketClient.Receive(arrRecvmsg);
 
        //将套接字获取到的字符数组转换为人可以看懂的字符串 
        string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
        if (x == 1)
        {
          Console.WriteLine("\r\n服务器:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n" + strRevMsg+"\r\n");
            
        }
        else
        {
          Console.WriteLine(strRevMsg + "\r\n");
          x = 1;
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine("远程服务器已经中断连接!" + ex.Message + "\r\n");
        break;
      }
    }
  }
 
  //发送字符信息到服务端的方法 
  public static void ClientSendMsg(string sendMsg)
  {
    //将输入的内容字符串转换为机器可以识别的字节数组   
    byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);
    //调用客户端套接字发送字节数组   
    SocketClient.Send(arrClientSendMsg);
  }  
}

测试结果:

server端:

client端:

代码下载地址:C-Socket_jb51.zip

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • php语言实现redis的客户端

    php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • c#中(&&,||)与(&,|)的区别详解

    这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • C#学习笔记- 随机函数Random()的用法详解

    下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25