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

扩展:
由于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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程宝库

一、前言我们在做Winform窗体程序开发的时候,会经常遇到窗体之间相互传值。假设有下面的一个场景:一个主窗体和一个子窗体,点击主窗体上面的按钮给子窗体传值,并在子窗体上面显示出来,一般会有如下几种方式实现。二、公共属 ...