Udp通讯(零基础)

时间:2022-01-22 14:41:39

前面学习了Tcp通讯之后听老师同学们讲到Udp也可以通讯,实现还要跟简单,没有繁琐的连接,所以最近学习了一下,记录下来以便忘记,同时也发表出来与大家相互学习,下面是我自己写的一个聊天例子,实现了群聊私聊等功能。

Udp通讯(零基础)

通讯类(UdpInfo)

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Model
{
[Serializable]
public class UdpInfo
{
public string Name { get; set; }
public string Ip { get; set; }
public string Port { get; set; }
public string Message { get; set; }
public int Types { get; set; }//消息的类型
public bool IsFist { get; set; }//判断加载的成员是否是第一个
public string ToName { get; set; }//与谁私聊
public string LoginName { get; set; }//新加入成员的名字
}
}

服务器(Server)

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Model; namespace Server
{
public partial class forUdp : Form
{
public forUdp()
{
InitializeComponent();
}
UdpClient server = null;
IPEndPoint ipEndPoint = null;
List<IPEndPoint> pointList = new List<IPEndPoint>();//成员集合
private delegate void BindDelegate(UdpInfo u);//(绑定信息)
BindDelegate bd = null;
private bool flag;//是否为添加的第一个成员
private string loginName;
private void Form1_Load(object sender, EventArgs e)
{
txtPort.Text = "";//默认的端口
}
public void Receices()//接收客户端的消息
{
while (true)
{
try
{
byte[] bytes = server.Receive(ref ipEndPoint);//获取消息
UdpInfo u = DeserializeObject(bytes) as UdpInfo;
bd = new BindDelegate(BindRtb);
this.Invoke(bd, u);
}
catch (Exception)
{
server.Close();//有异常关闭服务
}
}
}
public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
{
object newOjb = null;
if (pBytes == null)
return newOjb;
MemoryStream memory = new MemoryStream(pBytes);
memory.Position = ;
BinaryFormatter formatter = new BinaryFormatter();
newOjb = formatter.Deserialize(memory);
memory.Close();
return newOjb;
}
public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
{
if (pObj == null)
return null;
MemoryStream memory = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memory, pObj);
memory.Position = ;
byte[] read = new byte[memory.Length];
memory.Read(read, , read.Length);
memory.Close();
return read;
}
public void BindRtb(UdpInfo u) //添加信息,绑定信息
{
if(u.Types == )//如果消息类型为上线
{
pointList.Add(ipEndPoint);//添加成员
//u.Name = "1";
//获取需要的基本信息
loginName = u.Name;
u.Ip = ipEndPoint.ToString().Split(':')[];
u.Port = ipEndPoint.ToString().Split(':')[];
byte[] bytes = SerializeObject(u);
ListViewItem item = new ListViewItem(u.Name);//绑定添加到成员列表上
item.SubItems.Add(u.Ip);
item.SubItems.Add(u.Port);
lvInfo.Items.Add(item);//显示成员信息
BindListView(loginName);//成员发生改变的时候,发送成员信息给客户端,刷新客户端的成员信息
}
else if (u.Types == )//如果消息的类型是群聊的话就执行
{
foreach (ListViewItem items in lvInfo.Items)//循环每个成员
{
IPAddress ip = IPAddress.Parse(items.SubItems[].Text);
IPEndPoint ipEndPoint = new IPEndPoint(ip, Convert.ToInt32(items.SubItems[].Text));
byte[] bytes = SerializeObject(u);
server.Send(bytes, bytes.Length, ipEndPoint);//给每个用户发送信息
}
}
else if (u.Types == )//消息的类型是私聊
{
foreach(ListViewItem items in lvInfo.Items)
{
//如果该成员是指定成员才发送信息
if(u.ToName.Equals(items.SubItems[].Text))
{
IPAddress ip = IPAddress.Parse(items.SubItems[].Text);
IPEndPoint ipEndPoint = new IPEndPoint(ip, Convert.ToInt32(items.SubItems[].Text));
byte[] bytes = SerializeObject(u);
server.Send(bytes, bytes.Length, ipEndPoint);//发送消息给指定的用户
}
}
}
else if(u.Types == )//如果消息的类型是下线的话
{
IPEndPoint ipEndPoint = null;
foreach (ListViewItem items in lvInfo.Items)//循环每个成员
{
IPAddress ip = IPAddress.Parse(items.SubItems[].Text);
ipEndPoint = new IPEndPoint(ip, Convert.ToInt32(items.SubItems[].Text));
if(items.SubItems[].Text.Equals(u.Name))
{
lvInfo.Items.Remove(items);//从ListView集合中移除
pointList.Remove(ipEndPoint);//从List<IPEndPoint>集合中移除
continue;
}
byte[] bytes = SerializeObject(u);
server.Send(bytes, bytes.Length, ipEndPoint);//给每个用户发送信息
}
}
//服务器接收所有的消息
rtbMessage.Text += "\n" + u.Name + ":" + u.Message;
}
public void BindListView(string loginName) //有新成员加入的时候就绑定刷新成员列表
{
flag = true;
foreach (ListViewItem items in lvInfo.Items)//循环每个用户
{
foreach (ListViewItem item in lvInfo.Items)//给每个用户发送全部的成员信息
{
UdpInfo u = new UdpInfo();
u.Name = item.SubItems[].Text.ToString();
u.IsFist = flag;//添加第一个成员的时候因为要重新初始化客户端成员列表,而剩下的则不要初始化,所以要设置为true
flag = false;
u.LoginName = loginName;
u.Message = "上线了!";
u.Ip = item.SubItems[].Text.ToString();
u.Port = item.SubItems[].Text.ToString();
byte[] bytes = SerializeObject(u);
IPAddress ip = IPAddress.Parse(items.SubItems[].Text);
IPEndPoint ipp = new IPEndPoint(ip, Convert.ToInt32(items.SubItems[].Text));//得到成员的IPEndPoint
server.Send(bytes, bytes.Length, ipp);
}
}
}
private void 结束程序ToolStripMenuItem_Click(object sender, EventArgs e)
{
server.Close();
this.Dispose();
Application.Exit();
} private void 运行程序ToolStripMenuItem_Click(object sender, EventArgs e)
{
rtbMessage.Text = "可以发送消息过来了!";
int port = Convert.ToInt32(txtPort.Text);
server = new UdpClient(port);
ipEndPoint = new IPEndPoint(IPAddress.Any, port);
Thread t = new Thread(new ThreadStart(Receices));
t.Start();
}
}
}

客户端(Client)

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Model;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary; namespace Client
{
public partial class forUdp : Form
{
public forUdp()
{
InitializeComponent();
}
UdpClient client = null;
IPEndPoint ipEndPoints = null;
private delegate void BindDelegate(UdpInfo u);
BindDelegate bd = null;
private void forUdp_Load(object sender, EventArgs e)
{
txtIP.Text = "192.168.1.109";
txtPort.Text = "";
txtName.Text = "小哈";
} private void 运行程序ToolStripMenuItem_Click(object sender, EventArgs e)
{
rtbMessage.Text = "可以发送消息过去了!";
int port = Convert.ToInt32(txtPort.Text);
ipEndPoints = new IPEndPoint(IPAddress.Parse(txtIP.Text), port);
client = new UdpClient();
client.Connect(IPAddress.Parse(txtIP.Text), port);//关联此IP和端口
Send(new UdpInfo() {Name = txtName.Text,Message = "上线了!", Types = });
Thread t = new Thread(new ThreadStart(Receices));
t.Start();
} public void Receices()//接收客户端的消息
{
while (true)
{
try
{
byte[] bytes = client.Receive(ref ipEndPoints);
UdpInfo u = DeserializeObject(bytes) as UdpInfo;
bd = new BindDelegate(BindRtb);
this.Invoke(bd, u);
}
catch (Exception)
{
client.Close();
}
}
}
public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
{
object newOjb = null;
if (pBytes == null)
return newOjb;
MemoryStream memory = new MemoryStream(pBytes);
memory.Position = ;
BinaryFormatter formatter = new BinaryFormatter();
newOjb = formatter.Deserialize(memory);
memory.Close();
return newOjb;
}
public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
{
if (pObj == null)
return null;
MemoryStream memory = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memory, pObj);
memory.Position = ;
byte[] read = new byte[memory.Length];
memory.Read(read, , read.Length);
memory.Close();
return read;
}
public void BindRtb(UdpInfo u)//将消息添加到消息框中
{
if (u.Types == )
{
if (u.IsFist == true)
lvInfo.Items.Clear();
ListViewItem item = new ListViewItem(u.Name);
item.SubItems.Add(u.Ip);
item.SubItems.Add(u.Port);
lvInfo.Items.Add(item);
}
else if (u.Types == )//如果消息的类型是下线的话
{
IPEndPoint ipEndPoint = null;
foreach (ListViewItem items in lvInfo.Items)//循环每个成员
{
if (items.SubItems[].Text.Equals(u.Name))
{
IPAddress ip = IPAddress.Parse(items.SubItems[].Text);
ipEndPoint = new IPEndPoint(ip, Convert.ToInt32(items.SubItems[].Text));
lvInfo.Items.Remove(items);//从ListView集合中移除
continue;
}
}
}
foreach (ListViewItem items in lvInfo.Items)
{
if(items.SubItems[].Text.Equals(u.LoginName))
rtbMessage.Text += "\n" + u.Name + ":" + u.Message;
}
}
public void Send(UdpInfo u)//发送消息给服务器
{
byte[] bytes = SerializeObject(u);
client.Send(bytes, bytes.Length);
}
private void 结束程序ToolStripMenuItem_Click(object sender, EventArgs e)
{
Send(new UdpInfo() { Name = txtName.Text, Message = "下线了!", Types = });
client.Close();
Application.Exit();
} private void btnSend_Click(object sender, EventArgs e)
{
UdpInfo u = new UdpInfo() {
Name = txtName.Text, Message = rtbNews.Text, Types =
};
if (lvInfo.SelectedItems.Count > )//如果有选中的成员的话
{
u.Types = ;
u.ToName = lvInfo.SelectedItems[].SubItems[].Text;
}
Send(u);
lvInfo.SelectedItems.Clear();//清除上一次的痕迹
}
}
}