您的位置:首页 > 理论基础 > 计算机网络

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

2014-06-12 21:06 1236 查看
一. 实验要求

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:

服务器端:

a)定义一个User类来存放客户的信息,包括名称与端口。

b)定义一个存放User类型的List集合,用于存放所有在线客户,获取本机的IP地址,并制定一个端口号,然 
  后创建一个TcpListener对象,并通过调用将对象的Start方法在指定的端口进行监听。

c)在单独的线程中,循环调用AcceptTcpClient方法接受客户端的连接请求,并根据该方法的返回结果得到    与该客户端对应的TcpClient对象,然后把该对象存放到List集合中。

d)每得到一个新的TcpClient对象,就创建一个与该客户对应的线程,在线程中与对应的客户进行通信;当    收到的是“Login”信息时,就把该客户的名称加到在线列表中,并把接收到的包括用户名及随机产生的 
  端口在内的信息转发给所有在线客户;若收到的是“Logout”信息,则把该用户从在线列表中移除;若    收到的是“Talk”信息,则彼此进行通信。

客户端:

a)定义一个User类来存放客户的信息,包括名称与端
4000
口。

b)利用TcpClient的构造函数创建一个TcpClient对象,与服务器端建立
连接。

c)利用TcpClient对象的GetStream方法得到网络流,然后利用该网络流
与服务器进行数据传输。

d)创建一个线程监听指定的端口,循环接收并处理服务器发送过来的消 息。

e)完成工作后,向服务器发送关闭消息,并关闭与服务器的连接。

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

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

b)在每个用户随机产生的端口进行UDP监听,当用户接收到服务器转发的其他用户端口时,创建一个线程    循环接收并处理客户端发送过来的消息。

c)客户端与客户端发送消息时,指定想发送的那个客户端的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();

   }

四.程序运行效果图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐