C#基于TCP&UDP实现服务器与多个客户端之间的通信(客户端之间直接通信,不靠服务器端转发消息)

一、实验要求

1、Server支持多客户访问。

2、C与S之间使用TCP连接。

3.C与C之间直接通信(不是通过S传递)。

4、C与C之间直接通信既可以使用TCP,也可以使用UDP。

5、可以使用Socket,也可以使用TcpClient/UdpClient等。

二、设计思路

1、创建服务器端和客户端的主体框架:

        首先在服务器端的Windows窗体中添加5个Label控件,2个TextBox控件,2个RichTextBox控件,1个ListBox控件和1个Button控件;然后在客户端的Windows窗体中添加4个Label控件,1个TextBox控件,2个RichTextBox控件,1个ListBox控件,2个Button控件。建立程序的主要界面后,系统自动生成界面的主要窗口生成代码。在服务器端和客户端的每个按钮的代码段中,分别添加事件触发的处理代码。其中服务器端的2个TextBox用来存放IP地址和端口号,而ListBox用来显示当前连接服务器的客户端,RichTextBox用来显示双方的通信信息。


2、实现C/S的通信,使用的是TCP

      服务器端:

(1)、定义一个User类来存放客户的信息,包括名称与端口
(2)、定义一个存放User类型的List集合,用于存放所有在线客户,获取本机的IP地址,并制定一个端口号,然后创建一个TcpListener对象,并通过调用将对象的Start方法在指定的端口进行监听。
(3)、在单独的线程中,循环调用AcceptTcpClient方法接受客户端的连接请求,并根据该方法的返回结果得到与该客户端对应的TcpClient对象,然后把该对象存放到List集合中
(4)、每得到一个新的TcpClient对象,就创建一个与该客户对应的线程,在线程中与对应的客户进行通信当收到的是“Login”信息时,就把该客户的名称加到在线列表中,并把接收到的包括用户名及随机产生的端口在内的信息转发给所有在线客户;若收到的是“Logout”信息,则把该用户从在线列表中移除;若收到的是“Talk”信息,则彼此进行通信。


      客户端:

(1)、定义一个User类来存放客户的信息,包括名称与端口。
(2)、利用TcpClient的构造函数创建一个TcpClient对象,与服务器端建立 连接。
(3)、利用TcpClient对象的GetStream方法得到网络流,然后利用该网络流与服务器进行数据传输。
(4)、创建一个线程监听指定的端口,循环接收并处理服务器发送过来的消息。
(5)、完成工作后,向服务器发送关闭消息,并关闭与服务器的连接。

    3、实现C/C直接通信,使用的是UDP

(1)、在客户端,用户一旦连接上服务器,就随机产生一个端口,并把用户和此端口发给服务器,服务器再将各用户对应的名称及端口转发给所有在线用户,因此,服务器在C与C通信的过程中只是充当转发端口的角色,一旦用户得知要与之通信的用户的IP地址及端口时,就可直接通信。

(2)、在每个用户随机产生的端口进行UDP监听,当用户接收到服务器转发的其他用户端口时,创建一个线程循环接收并处理客户端发送过来的消息。
(3)、客户端与客户端发送消息时,指定想发送的那个客户端的IP地址和端口,就可以进行通信。

三、TCP+UDP通信核心代码:

服务器端:

 /// <summary>保存连接的所有用户</summary>
   private List<User> userList = new List<User>();
   /// <summary>使用的本机IP地址</summary>
   IPAddress localAddress;
   /// <summary>监听端口</summary>
   private const int port = 51888;
   private TcpListener myListener;
   /// <summary>是否正常退出所有连接线程 </summary>
   bool isNormalExit = false;
   IPEndPoint iep;
   IPHostEntry local;
   User user;
   TcpClient newClient;

   public Server()
   {
       InitializeComponent();
       UserNameList.HorizontalScrollbar = true;
       local = Dns.GetHostByName(Dns.GetHostName());
       iep = new IPEndPoint(local.AddressList[0], port);
       this.iPTextBox.Text = local.AddressList[0].ToString();
       this.portTextBox.Text = port.ToString();
   }

   private void start_button_Click(object sender, EventArgs e)
   { 
   }

   private void Server_Load(object sender, EventArgs e)
   {
       myListener = new TcpListener(iep);
       myListener.Start();
       AddItemToRichTextBox(string.Format("服务器已启动\n"));
       //创建一个线程监听客户端连接请求
       Thread myThread = new Thread(ListenClientConnect);
       myThread.Start();
       myThread.IsBackground = true;
       iPTextBox.Enabled = false;
       portTextBox.Enabled = false;   
   }

   /// <summary>接收客户端连接</summary>
   private void ListenClientConnect()
   {
       newClient = null;
       while (true)
       {
           try
           {
               newClient = myListener.AcceptTcpClient();
           }
           catch
           {
               break;
           }

           //每接收一个客户端连接,就创建一个对应的线程循环接收该客户端发来的消息
           user = new User(newClient);
           Thread threadReceive = new Thread(ReceiveData);
           threadReceive.Start(user);
           userList.Add(user);
           SendMessage(string.Format("Talk,Hello I am Server!"));
           threadReceive.IsBackground = true;
       }
   }

   /// <summary>
   /// 发送信息给所有客户
   /// </summary>
   /// <param name="user">指定发给哪个用户</param>
   /// <param name="message">信息内容</param>
   private void SendToAllClient(User user, string message)
   {
       string command = message.Split(',')[0].ToLower();
       if (command == "login")
       {
           for (int i = 0; i < userList.Count; i++)
           {
               SendToClient(userList[i],message);
               if (userList[i].userName != user.userName)
               {
               SendToClient(user,"login,"+userList[i].userName+","+userList[i].userPort);
               }
           }
       }
       else if (command == "logout")
       {
           for (int i = 0; i < userList.Count; i++)
           {
               if (userList[i].userName != user.userName)
               {
                   SendToClient(userList[i],message);
               }
           }
       }
   }

客户端:

    private bool isExit = false;

   //存放客户端名称及端口
   private List<User> userUdpList = new List<User>();
   private TcpClient client;
   private BinaryReader br;
   private BinaryWriter bw;
   private UdpClient receiveUdpClient;
   private UdpClient sendUdpClient;
   IPAddress IP;
   int random_port;
   User user;

   public Client()
   {
       InitializeComponent();
       Random r = new Random((int)DateTime.Now.Ticks);
       user_textBox.Text = "User" + r.Next(100,999);
       user_listBox.HorizontalScrollbar = true;
   }

   private void Client_Load(object sender, EventArgs e)
   {
   }

   private void login_button_Click(object sender, EventArgs e)
   {
       login_button.Enabled = false;
       user_textBox.Enabled = false;
       try
       {
           client = new TcpClient(Dns.GetHostName(),51888);
           //随机产生一个端口,并在此端口进行UDP监听
           Random random = new Random();
           random_port = random.Next(60000);
           IP=Dns.GetHostByName(Dns.GetHostName()).AddressList[0];
           IPEndPoint local = new IPEndPoint(IP,random_port);
           receiveUdpClient = new UdpClient(local);
       }
       catch
       {
           MessageBox.Show("连接失败!");
           login_button.Enabled = true;
           return;
       }
       NetworkStream networkStream = client.GetStream();
       br = new BinaryReader(networkStream);
       bw = new BinaryWriter(networkStream);
       //把用户名及随机产生的端口发到服务器
       SendMessageToServer("Login," + user_textBox.Text + "," + random_port);
       //接收服务器消息的线程
       Thread threadReceive = new Thread(new ThreadStart(ReceiveFromServer));
       threadReceive.IsBackground = true;
       threadReceive.Start();
   }

四、程序运行效果图


————————————————
版权声明:本文为CSDN博主「scau_11jkx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/scau_11jkx/article/details/30294363

 

https://blog.csdn.net/scau_11jkx/article/details/30294363?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-18-30294363.nonecase

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中进行socket网络编程可以实现一个服务器多个客户端通信,以下是一个简单的示例: 服务器端代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Server { class Program { static void Main(string[] args) { // 创建一个TCP/IP socket对象 Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 绑定IP地址和端口号 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8888); listener.Bind(localEndPoint); // 开始监听连接请求 listener.Listen(10); Console.WriteLine("等待客户端连接..."); while (true) { // 接受来自客户端的连接请求 Socket handler = listener.Accept(); // 接收客户端发送的数据 byte[] buffer = new byte[1024]; int bytesRead = handler.Receive(buffer); string data = Encoding.ASCII.GetString(buffer, 0, bytesRead); Console.WriteLine($"接收到客户端数据:{data}"); // 向客户端发送响应数据 byte[] responseBytes = Encoding.ASCII.GetBytes("收到你的消息了!"); handler.Send(responseBytes); // 关闭连接 handler.Shutdown(SocketShutdown.Both); handler.Close(); } } } } ``` 客户端代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Client { class Program { static void Main(string[] args) { // 创建一个TCP/IP socket对象 Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 连接服务器 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); IPEndPoint remoteEP = new IPEndPoint(ipAddress, 8888); sender.Connect(remoteEP); Console.WriteLine("连接服务器成功!"); // 向服务器发送数据 string message = "Hello, Server!"; byte[] bytes = Encoding.ASCII.GetBytes(message); sender.Send(bytes); // 接收服务器的响应数据 byte[] buffer = new byte[1024]; int bytesRead = sender.Receive(buffer); string response = Encoding.ASCII.GetString(buffer, 0, bytesRead); Console.WriteLine($"接收到服务器响应:{response}"); // 关闭连接 sender.Shutdown(SocketShutdown.Both); sender.Close(); Console.ReadKey(); } } } ``` 以上代码可以实现一个简单的服务器客户端通信,如果想实现多个客户端同时连接服务器,可以使用多线程或异步编程来处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值