这是学习Socket制作的,是两个项目,分别为客户端和服务器端,在测试的时候需要同时运行起来。
UDP一般和TCP协议进行比较,具体不同可百度大神的文章学习。根据我的理解,UDP协议中最重要的两个方法是ReceiveFrom()和SendTo(), “UDP应用上已经无严格意义上的真正的服务器和客户端之分了”,其实就是通过IP地址和端口进行数据的发送和接收。
在学习的过程中碰到了几个难点:
1、无论是服务端和客户端在接收信息的时候,设置缓存区接收信息如下
byte[] data = new byte[1024]; recv= SocClient.ReceiveFrom(data, ref RemotePoint); this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += (RemotePoint.ToString()+Encoding.Default.GetString(data,0,recv)); }));
如果设置的读取信息语句如下,
Encoding.Default.GetString(data)
则文本框上就会将data中1204个字节都显示出来,很影响效果,所以改成
Encoding.Default.GetString(data,0,recv)
则显示的正常。
2、由于接收信息的是个单独的线程,如果给主界面上的文本框中添加文字,则会提示“调用线程无法访问此对象,因为另一个线程拥有该对象”,所以设置如下语句进行解决:
this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += (RemotePoint.ToString()+Encoding.Default.GetString(data,0,recv)); }));
下面贴出代码:
服务端 前端:
<Window x:Class="UdpServe.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:UdpServe" mc:Ignorable="d" Title="服务器端" Height="375" Width="524"> <Grid> <Button Name="btn_send" Content="发送信息" HorizontalAlignment="Left" Margin="333,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_send_Click" /> <TextBox Name="tblock_message" ScrollViewer.VerticalScrollBarVisibility="Auto" Background="Cornsilk" HorizontalAlignment="Left" Margin="34,10,0,0" VerticalAlignment="Top" Height="208" Width="464"/> <Button Name="btn_connect" Content="开启服务" HorizontalAlignment="Left" Margin="243,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_connect_Click"/> <Label Content="IP地址" HorizontalAlignment="Left" Margin="33,269,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_Ip" HorizontalAlignment="Left" Height="23" Margin="91,272,0,0" VerticalAlignment="Top" Width="136" Text="0.0.0.0" IsEnabled="False"/> <Button Name="btn_clear" Content="清屏" HorizontalAlignment="Left" Margin="424,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_clear_Click" /> <Label Content="昵称" HorizontalAlignment="Left" Margin="33,241,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_ServeName" HorizontalAlignment="Left" Height="23" Margin="91,244,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="136" Text="阿森纳"/> <Label Content="端口" HorizontalAlignment="Left" Margin="33,301,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_Port" HorizontalAlignment="Left" Height="23" Margin="91,304,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="136" Text="8080"/> <TextBox x:Name="tb_message" HorizontalAlignment="Left" Height="54" Margin="243,273,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="255"/> </Grid> </Window>
服务端 后端:
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows; namespace UdpServe { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); tb_Ip.Text = getIPAddress(); } private IPEndPoint ipLocalPoint; private EndPoint RemotePoint; private Socket mySocket; /// <summary> /// 获得本机局域网IP地址 /// </summary> private string getIPAddress() { string HostName = Dns.GetHostName(); IPAddress[] AddressList = Dns.GetHostByName(HostName).AddressList; if (AddressList.Length < 1) { return ""; } return AddressList[0].ToString(); } /// <summary> /// 服务端监听 /// </summary> private void serverListen() { try { //与 address 关联的端口号,或为 0 以指定任何可用端口。port 以主机顺序排列。 IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); RemotePoint = (EndPoint)(sender); int recv; //启动一个新的线程,执行方法this.ReceiveHandle,以便在一个独立的进程中执行数据接收的操作 while (true) { byte[] data = new byte[1024]; recv= mySocket.ReceiveFrom(data, ref RemotePoint); this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += (RemotePoint.ToString()+Encoding.Default.GetString(data,0,recv)); })); } } catch (Exception ex) { this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += ex.Message + "\n"; })); } } /// <summary> /// 建立连接 /// </summary> private void btn_connect_Click(object sender, RoutedEventArgs e) { try { //定义网络类型,数据连接类型和网络协议UDP mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); ipLocalPoint = new IPEndPoint(IPAddress.Parse(tb_Ip.Text), int.Parse(tb_Port.Text)); mySocket.Bind(ipLocalPoint); Thread thread = new Thread(new ThreadStart(serverListen)); thread.IsBackground = true; thread.Start(); tblock_message.Text += "服务器建立连接" + "\n"; } catch (Exception ex) { tblock_message.Text += ex.Message + "\n"; } } /// <summary> /// 发送信息 /// </summary> private void btn_send_Click(object sender, RoutedEventArgs e) { try { byte[] mess = Encoding.Default.GetBytes(tb_ServeName.Text + ":" + tb_message.Text+"\n"); mySocket.SendTo(mess, mess.Length, SocketFlags.None, RemotePoint); tblock_message.Text += Encoding.Default.GetString(mess); } catch (Exception ex) { tblock_message.Text += ex.Message+ "\n"; } } private void btn_clear_Click(object sender, RoutedEventArgs e) { tblock_message.Text = ""; } } }
客户端 前端:
<Window x:Class="UdpClient.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:UdpClient" mc:Ignorable="d" Title="我是客户端之1号机" Height="375" Width="524"> <Grid> <Button Name="btn_send" Content="发送信息" HorizontalAlignment="Left" Margin="333,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_send_Click" /> <TextBox Name="tblock_message" ScrollViewer.VerticalScrollBarVisibility="Visible" Background="Cornsilk" HorizontalAlignment="Left" Margin="34,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="208" Width="464"/> <Button Name="btn_connect" Content="开启服务" HorizontalAlignment="Left" Margin="243,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_connect_Click"/> <Label Content="IP地址" HorizontalAlignment="Left" Margin="33,269,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_Ip" HorizontalAlignment="Left" Height="23" Margin="91,272,0,0" VerticalAlignment="Top" Width="136" Text="0.0.0.0" IsEnabled="False"/> <Button Name="btn_clear" Content="清屏" HorizontalAlignment="Left" Margin="424,244,0,0" VerticalAlignment="Top" Width="75" Click="btn_clear_Click" /> <Label Content="昵称" HorizontalAlignment="Left" Margin="33,241,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_ServeName" HorizontalAlignment="Left" Height="23" Margin="91,244,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="136" Text="利物浦"/> <Label Content="端口" HorizontalAlignment="Left" Margin="33,301,0,0" VerticalAlignment="Top"/> <TextBox x:Name="tb_Port" HorizontalAlignment="Left" Height="23" Margin="91,304,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="136" Text="8090"/> <TextBox x:Name="tb_message" HorizontalAlignment="Left" Height="54" Margin="243,273,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="255"/> </Grid> </Window>
客户端 后端:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; 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; namespace UdpClient { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } Socket SocClient; IPEndPoint IpClient; EndPoint RemotePoint; IPEndPoint IpServe; /// <summary> /// 建立连接 /// </summary> private void btn_connect_Click(object sender, RoutedEventArgs e) { try { //定义网络类型,数据连接类型和网络协议UDP SocClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //设置服务IP,设置UDP端口号 IpClient = new IPEndPoint(IPAddress.Parse(tb_Ip.Text), int.Parse(tb_Port.Text)); SocClient.Bind(IpClient); Thread thread = new Thread(new ThreadStart(serverListen)); thread.IsBackground = false; thread.Start(); tblock_message.Text += "客户端建立连接" + "\n"; } catch (Exception ex) { tblock_message.Text += ex.Message + "\n"; } } private void serverListen() { try { //得到服务器IP //与 address 关联的端口号,或为 0 以指定任何可用端口。port 以主机顺序排列。 IpServe = new IPEndPoint(IPAddress.Parse("192.168.0.114"), 8080); RemotePoint = (EndPoint)(IpServe); int recv; //启动一个新的线程,执行方法this.ReceiveHandle,以便在一个独立的进程中执行数据接收的操作 while (true) { byte[] data = new byte[1024]; recv= SocClient.ReceiveFrom(data, ref RemotePoint); this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += (RemotePoint.ToString()+Encoding.Default.GetString(data,0,recv)); })); } } catch (Exception ex) { this.Dispatcher.Invoke(new Action(() => { tblock_message.Text += ex.Message + "\n"; })); } } private void btn_send_Click(object sender, RoutedEventArgs e) { try { byte[] mess = Encoding.Default.GetBytes(tb_ServeName.Text + ":" + tb_message.Text + "\n"); SocClient.SendTo(mess, mess.Length, SocketFlags.None, RemotePoint); tblock_message.Text += Encoding.Default.GetString(mess); } catch (Exception ex) { tblock_message.Text += ex.Message + "\n"; } } private void btn_clear_Click(object sender, RoutedEventArgs e) { tblock_message.Text = ""; } } }