文章目录

  • 实验环境
  • 实现效果
  • 实现原理
  • 一些需要注意的点
  • 源码及详细注释
    • MainWindow后台代码
    • NetMeetingClient前台设计代码
    • NetMeetingClient后台代码
    • RoomService类源码

实验环境

WindowsServer2012+vs2010

实现效果

单机MainWindow里面的“网络会议室”按钮,然后弹出三个客户端,三个客户端端口和姓名已分配
每个客户端可以点击登陆按钮,进入会议室,只要登入的客户端,每个客户端左边的会议室成员列表都会实时更新
登陆进去的客户端,可以参与讨论,消息共享。
单机退出按钮,关闭客户端,并且其余未退出的客户端会更新在线人员列表。

实现原理

主要是利用套接字实现发送和接受消息,然后利用多播和单播结合来实现会议讨论功能。
具体功能设计思路解析如图:
一、

二、

三、

四、

五、
发消息聊天比较简单,直接RoomService发广播就好了。

一些需要注意的点

  • 三个客户端自始至终都只监听8000,只跟RoomService通信
  • 用户登录,先告知他当前在线成员,再将他加入用户列表,注意顺序,否则会出现一个名字加两遍
  • 当收到用户登录信息,RoomService在实例化User时,要注意,User的UserEndPoint是该用户端口信息,后边ShowCurrentUsers要用到

ps:这个程序目前的缺点是,客户端退出之后,窗口就关闭了,没有办法再次加入会议室,我本来想着通过登录标志isLogin和关闭标志isExit,来实现单机退出按钮时,不关闭窗口,只退出多播组。这样虽然成功了,但是再次加入会议室的时候,报错,提示套接字只能使用一次。。。。。。算咯,以后会了再改吧

源码及详细注释

MainWindow后台代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.Sockets;namespace ch11
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{private IPAddress ip;public MainWindow(){InitializeComponent();//获取本机ip地址IPAddress[] ipes = Dns.GetHostAddresses(Dns.GetHostName());foreach (IPAddress v in ipes){if (v.AddressFamily == AddressFamily.InterNetwork){ ip = v; break; }}}//启动会议室程序private void button1_Click(object sender, RoutedEventArgs e){int servicePort = 8000;//RoomService端口RoomService service = new RoomService(ip, servicePort);//先启动RoomServiceShowClient("客户端1", "张三", -360, -50, 8001, servicePort);ShowClient("客户端2", "李四", 210, -50, 8002, servicePort);ShowClient("客户端3", "王五", -100, 140, 8003, servicePort);           }private void ShowClient(string title, string userName,double dx, double dy, int port, int servicePort){NetMeetingClient w = new NetMeetingClient(){Title = title,Owner = this,Left = this.Left + dx,Top = this.Top + dy,localEndPoint = new IPEndPoint(ip, port),//这里是他们自己的端口remoteEndPoint = new IPEndPoint(ip, servicePort)//这里是8000};w.UserName = userName;w.Show();}}
}

NetMeetingClient前台设计代码

<Window x:Class="ch11.NetMeetingClient"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="网络会议室" Height="354" Width="480"><Grid><GroupBox Header="会议室成员" Height="185" HorizontalAlignment="Left" Margin="21,87,0,0" Name="groupBox1" VerticalAlignment="Top" Width="133"><Grid><ListBox Height="142" HorizontalAlignment="Left" Margin="6,6,0,0" Name="listBox1" VerticalAlignment="Top" Width="97" /></Grid></GroupBox><GroupBox Header="发言内容" Height="179" HorizontalAlignment="Left" Margin="171,87,0,0" Name="groupBox2" VerticalAlignment="Top" Width="261"><Grid><Grid.RowDefinitions><RowDefinition Height="53*" /><RowDefinition Height="25*" /></Grid.RowDefinitions><ListBox Grid.RowSpan="2" Height="142" HorizontalAlignment="Left" Margin="6,6,0,0" Name="listBox2" VerticalAlignment="Top" Width="237" /></Grid></GroupBox><Label Content="发言:" Height="32" HorizontalAlignment="Left" Margin="22,281,0,0" Name="label1" VerticalAlignment="Top" Width="60" /><TextBox Height="32" HorizontalAlignment="Right" Margin="0,281,110,0" Name="textBox1" VerticalAlignment="Top" Width="260" /><Button Content="发送" Height="23" HorizontalAlignment="Left" Margin="371,285,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" /><Label Content="用户名:" Height="28" HorizontalAlignment="Left" Margin="27,21,0,0" Name="label2" VerticalAlignment="Top" /><TextBox Height="24" HorizontalAlignment="Left" Margin="91,21,0,0" Name="textBox2" VerticalAlignment="Top" Width="95" /><Button Content="登录(进入会议室)" Height="22" HorizontalAlignment="Left" Margin="224,23,0,0" Name="button2" VerticalAlignment="Top" Width="124" Click="button2_Click" /><Button Content="退出" Height="23" HorizontalAlignment="Left" Margin="371,22,0,0" Name="button3" VerticalAlignment="Top" Width="75" Click="button3_Click" /></Grid>
</Window>

NetMeetingClient后台代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Net;
using System.Net.Sockets;
using System.Threading;namespace ch11
{/// <summary>/// NetMeetingClient.xaml 的交互逻辑/// </summary>public partial class NetMeetingClient : Window{public IPEndPoint localEndPoint { get; set; }public IPEndPoint remoteEndPoint;private UdpClient client;public string UserName;private IPAddress multicastAddress = IPAddress.Parse("224.0.1.1");private bool isExit = false;//窗口是否关闭private bool isLogin = false;//是否登陆public NetMeetingClient(){InitializeComponent();this.Loaded += NetMeeting_Loaded;this.Closing += NetMeeting_Closing;//加载关闭属性}//新启动的窗口为用户名一栏赋值  并设置“退出”按钮void NetMeeting_Loaded(object sender, RoutedEventArgs e) {textBox2.Text=this.UserName;button3.IsEnabled = false;}//关闭窗口void NetMeeting_Closing(object sender, System.ComponentModel.CancelEventArgs e){if (isLogin){SendMessage("Logout," + UserName);//告诉管理员 用户退出}isExit = true;//窗口关闭}//给remoteEndPoint发送消息private void SendMessage(string Sendstring){byte[] bytes = System.Text.Encoding.Unicode.GetBytes(Sendstring);client.Send(bytes, bytes.Length, remoteEndPoint);}//用户列表添加用户private void AddUser(string userName){Action act = delegate() { listBox1.Items.Add(userName); };listBox1.Dispatcher.Invoke(act);}//用户列表移除用户private void RemoveUser(string userName){for (int i = 0; i < listBox1.Items.Count; i++) {if (listBox1.Items[i].ToString() == userName) {Action act = delegate() { listBox1.Items.Remove(userName); };listBox1.Dispatcher.Invoke(act);break;}}}//聊天列表添加信息private void AddTalk(string format,params object[] args){string content = string.Format(format, args);Action act = delegate() { listBox2.Items.Add(content); };listBox2.Dispatcher.Invoke(act);}//登录按钮private void button2_Click(object sender, RoutedEventArgs e){client = new UdpClient(localEndPoint);//生成套接字client.JoinMulticastGroup(multicastAddress);//加入多播组SendMessage("Login," + UserName);//告诉8000端口 用户登录Thread t1 = new Thread(ReceiveDate);//委托线程监听8000端口消息t1.Start();isLogin = true;//登陆标志button2.IsEnabled = false;//登陆按钮button3.IsEnabled = true;//退出按钮}//监听并接收信息public void ReceiveDate(){while (isExit == false){try{byte[] result = client.Receive(ref remoteEndPoint);//接受8000端口信息string message = Encoding.Unicode.GetString(result);string[] split = message.Split(',');//分割string command = split[0];string args = message.Remove(0, split[0].Length + 1);switch (command){case "Login":{string userName = args;AddUser(userName);break;}case "List":  //添加已在线成员列表{for (int i = 1; i < split.Length; i++){AddUser(split[i]);}break; }case "Logout":{string userName = args;RemoveUser(userName);break;}case "Say":{AddTalk("{0}:{1}", split[1], args.Remove(0, split[1].Length + 1));break;}}}catch (Exception ex){MessageBox.Show(ex.ToString());}}client.DropMulticastGroup(multicastAddress);//退出多播组client.Close();//关闭套接字}private void button3_Click(object sender, RoutedEventArgs e)//退出{this.Close();//关闭窗口  退出信息在关闭窗口的属性方法里面写着}private void button1_Click(object sender, RoutedEventArgs e)//发送{SendMessage("Say," + UserName + "," + textBox1.Text);textBox1.Text = "";//发送完消息  输入框置为空}}
}

RoomService类源码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows;namespace ch11
{class RoomService{private Dictionary<string, User> users = new Dictionary<string, User>();public IPEndPoint localEndPoint { get; set; }private UdpClient client;private IPAddress multicastAddress = IPAddress.Parse("224.0.1.1");//多播地址public bool isExit = false;public RoomService(IPAddress localAddress, int servicePort) {localEndPoint = new IPEndPoint(localAddress, servicePort);client = new UdpClient(localEndPoint);Thread t1 =new Thread(ReceiveDate);//加入多播组 监听所有端口信息t1.Start();}public void CloseSerivce(){isExit = true;//while循环结束 退出多播组}public void ReceiveDate(){IPEndPoint remote = null;//监听所有端口信息client.JoinMulticastGroup(multicastAddress);while (isExit==false){try {byte[] result = client.Receive(ref remote);//接收所有端口信息string message = Encoding.Unicode.GetString(result);string[] split = message.Split(',');//分割switch (split[0]){case "Login":{string userName = split[1];if (users.ContainsKey(userName)){string str = "CanNotLogin," + "已有该名称";byte[] bytess = Encoding.Unicode.GetBytes(str);client.Send(bytess, bytess.Length, remote);}else {User user = new User(){UserName=userName,UserEndPoint = remote//注意:此时的remote是当前正在登录的用户的端口};ShowCurrentUsers(user);//要先为该用户发送已在线人员信息users.Add(userName, user);//再将此用户加入字典Multicast(message);//广播该用户上线信息 使其他客户端将其加入列表}break;}case "Logout":{string userName = split[1];users.Remove(userName);//移除该用户Multicast(message);//广播移除信息break;}case "Say":{Multicast(message);//广播消息break;}}}catch(Exception ex){MessageBox.Show(ex.ToString());}}client.DropMulticastGroup(multicastAddress);//退出多播组client.Close();}//用户刚刚登陆 先将会议室现有人员列表发送给该用户private void ShowCurrentUsers(User user){if (users.Count == 0) return;string s = "List";//遍历现有的在线人员列表foreach (var v in users.Keys) {s += "," + v;}byte[] bytes = Encoding.Unicode.GetBytes(s);client.Send(bytes, bytes.Length, user.UserEndPoint);//发送给该用户  UserEndPoint}//在会议室广播private void Multicast(string message){string hostname = multicastAddress.ToString();byte[] bytes = Encoding.Unicode.GetBytes(message);for (int i = 8001; i < 8004; i++) {client.Send(bytes, bytes.Length, hostname,i);//将登陆信息发给所有客户端}}}public class User{public string UserName{get;set;}public IPEndPoint UserEndPoint{get;set;}}
}

C#网络编程----使用UdpClient实现网络会议讨论(详解)相关推荐

  1. 网络编程中的SO_REUSEADDR和SO_REUSEPORT参数详解

    1.SO_REUSEADDR: 在BSD中,SO_REUSEADDR选项有两个用户: 如果有socket绑定了0.0.0.0:port:设置该参数后,其他socket可以绑定本机ip:port.(该功 ...

  2. 手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解

    2019独角兽企业重金招聘Python工程师标准>>> 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中--酝 ...

  3. Linux后端服务器网络编程之线程模型丨reactor模型详解

    前言   上一篇文章<后端服务器网络编程之 IO 模型>中讲到服务器端高性能网络编程的核心在于架构,而架构的核心在于进程/线程模型的选择.本文将主要介绍传统的和目前流行的进程/线程模型,在 ...

  4. 【Java网络编程与IO流】Http协议详解以及面试有关问题

    HTTP协议详解以及面试有关题目 1 HTTP请求 一个HTTP请求报文由请求行.请求头部.空行和请求数据四个部分组成. 1.1 请求行 请求行中有请求方法字段.URL字段和HTTP协议版本3个字段组 ...

  5. Linux 网络编程学习笔记——三、TCP 协议详解

    目录 一.TCP 服务的特点 传输层协议主要有 TCP 协议和 UDP 协议,前者相对于后者的特点是:面向连接.字节流和可靠传输. 使用 TCP 协议通信的双方必须先建立连接,然后才能开始数据的读写. ...

  6. C++ tcpip网络编程中listen函数和accept函数详解和区别

    listen函数 摘要:listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程.在TCP服务器编程中listen函数把进程变为一个服务器,并指定 ...

  7. [C#]网络编程系列专题二:HTTP协议详解

    转自:http://www.cnblogs.com/zhili/archive/2012/08/18/2634475.html 我们在用Asp.net技术开发Web应用程序后,当用户在浏览器输入一个网 ...

  8. 【Linux网络编程】TCP 和 UDP 数据报格式详解

    TCP 报文格式 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. TCP 报文段的报头有 10 个必需的字段和 ...

  9. Linux 网络编程学习笔记——二、IP 协议详解

    目录 一.IP 服务的特点 IP 协议为上层协议提供无状态.无连接.不可靠的服务: 无状态(stateless):指 IP 通信双方不同步传输数据的状态信息,因此所有 IP 数据报的发送.传输和接收都 ...

  10. 网络编程基础一:TCP/IP 协议详解

    前言 我们知道两个进程如果需要进行通讯最基本的一个前提[能够唯一的标示一个进程],在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候 ...

最新文章

  1. 高维多元数据拟合回归如何进行???
  2. bom event周期_DOM-BOM-EVENT(1)
  3. 6号板编译失败找不到arm-none-linux-gnueabi-gcc
  4. linux-tar命令详解
  5. 四则运算个人项目进展
  6. android R编译OTA时报“ExternalError: Invalid ro.product.property_source_order”解决方法
  7. 小鹏、蔚来相继车祸,自动驾驶四字不等于“全自动”,也分等级!
  8. AWS想到办法让Alexa能在毫秒内做出回复
  9. python pyquery不规则数据的抓取_11. 数据提取-PyQuery
  10. Web的测试内容和方法【转贴】
  11. 2021最新对比学习(Contrastive Learning)在各大顶会上的经典必读论文解读
  12. 分布式数据:缓存技术
  13. 【青梅快讯】惊喜不断,Greenplum 最新版本 6.13.0已发布
  14. Tek DPO2024B示波器和电流探头A622的使用
  15. 微信小游戏排行榜卡顿或无法滑动
  16. 为什么拼多多推广出价没人点击?新店铺怎么推广?
  17. 【2019年02月21日】股息率分红最高排名
  18. Python批量处理Excel办公自动化
  19. 懒汉延迟加载设计模式反射注解
  20. http判断缓存是否有效,为什么有了last-modified还需要etag呢?

热门文章

  1. 黑客的克星或叫“白客”
  2. solr6.0.0 + tomcat8 配置问题
  3. 查看Linux服务器网络状态
  4. VMware基础架构和运营管理
  5. GNS3中RIP的过滤和修改
  6. Exchange Server 2007邮箱存储服务器的容量规划和性能调优(下)
  7. 如何用大数据开发套件周期调度机器学习算法
  8. centos6 系统安装 system-config-kickstart 工具
  9. haproxy之安装与配置详解
  10. sublime text 前端开发插件安装和配置