• 与众不同 windows phone (31) Communication(通信)之基于 Socket UDP 开发一个多人聊天室


    [索引页]
    [源码下载]


    与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室



    作者:webabcd


    介绍
    与众不同 windows phone 7.5 (sdk 7.1) 之通信

    • 实例 - 基于 Socket UDP 开发一个多人聊天室



    示例
    1、服务端
    Main.cs

    /*
     * Socket UDP 聊天室的服务端
     * 
     * 注:udp 报文(Datagram)的最大长度为 65535(包括报文头)
     */
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    using System.Net.Sockets;
    using System.Net;
    using System.Threading;
    using System.IO;
    
    namespace SocketServerUdp
    {
        public partial class Main : Form
        {
            SynchronizationContext _syncContext;
    
            System.Timers.Timer _timer;
    
            // 客户端终结点集合
            private List<IPEndPoint> _clientList = new List<IPEndPoint>();
    
            public Main()
            {
                InitializeComponent();
    
                // UI 线程
                _syncContext = SynchronizationContext.Current;
    
                // 启动后台线程接收数据
                Thread thread = new Thread(new ThreadStart(ReceiveData));
                thread.IsBackground = true;
                thread.Start();
    
                // 每 10 秒运行一次计时器所指定的方法,群发信息
                _timer = new System.Timers.Timer();
                _timer.Interval = 10000d;
                _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
                _timer.Start();
            }
    
            // 接收数据
            private void ReceiveData()
            {
                // 实例化一个 UdpClient,监听指定端口,用于接收信息
                UdpClient listener = new UdpClient(3367);
                // 客户端终结点
                IPEndPoint clientEndPoint = null;
    
                try
                {
                    while (true)
                    {
                        // 一直等待,直至接收到数据为止(可以获得接收到的数据和客户端终结点)
                        byte[] bytes = listener.Receive(ref clientEndPoint);
                        string strResult = Encoding.UTF8.GetString(bytes);
    
                        OutputMessage(strResult);
    
                        // 将发送此信息的客户端加入客户端终结点集合
                        if (!_clientList.Any(p => p.Equals(clientEndPoint)))
                            _clientList.Add(clientEndPoint);
                    }
                }
                catch (Exception ex)
                {
                    OutputMessage(ex.ToString());
                }
            }
    
            private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                // 每 10 秒群发一次信息
                SendData(string.Format("webabcd 对所有人说:大家好! 【信息来自服务端 {0}】", DateTime.Now.ToString("hh:mm:ss")));
            }
    
            // 发送数据
            private void SendData(string data)
            {
                // 向每一个曾经向服务端发送过信息的客户端发送信息
                foreach (IPEndPoint ep in _clientList)
                {
                    // 实例化一个 UdpClient,用于发送信息
                    UdpClient udpClient = new UdpClient();
    
                    try
                    {
                        byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);
                        // 发送信息到指定的客户端终结点,并返回发送的字节数
                        int count = udpClient.Send(byteData, byteData.Length, ep);
                    }
                    catch (Exception ex)
                    {
                        OutputMessage(ex.ToString());
                    }
    
                    // 关闭 UdpClient
                    // udpClient.Close();
                }
            }
    
            // 在 UI 上输出指定信息
            private void OutputMessage(string data)
            {
                _syncContext.Post((p) => { txtMsg.Text += p.ToString() + "\r\n"; }, data);
            }
        }
    }


    2、客户端
    UdpPacketEventArgs.cs

    /*
     * 演示 ASM 和 SSM 用
     */
    
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    namespace Demo.Communication.SocketClient
    {
        public class UdpPacketEventArgs : EventArgs
        {
            // UDP 包的内容
            public string Message { get; set; }
            // UDP 包的来源的 IPEndPoint 
            public IPEndPoint Source { get; set; }
    
            public UdpPacketEventArgs(byte[] data, IPEndPoint source)
            {
                this.Message = System.Text.Encoding.UTF8.GetString(data, 0, data.Length);
                this.Source = source;
            }
        }
    }

    UdpDemo.xaml

    <phone:PhoneApplicationPage 
        x:Class="Demo.Communication.SocketClient.UdpDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait" Orientation="Portrait"
        mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
        shell:SystemTray.IsVisible="True">
    
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <StackPanel HorizontalAlignment="Left">
    
                <ScrollViewer x:Name="svChat" Height="400">
                    <TextBlock x:Name="txtChat" TextWrapping="Wrap" />
                </ScrollViewer>
    
                <TextBox x:Name="txtName" />
                <TextBox x:Name="txtInput" KeyDown="txtInput_KeyDown" />
                <Button x:Name="btnSend" Content="发送" Click="btnSend_Click" />
    
            </StackPanel>
        </Grid>
    
    </phone:PhoneApplicationPage>

    UdpDemo.xaml.cs

    /*
     * Socket UDP 聊天室的客户端
     */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;
    
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    
    namespace Demo.Communication.SocketClient
    {
        public partial class UdpDemo : PhoneApplicationPage
        {
            // 客户端 Socket
            private Socket _socket;
    
            // 用于发送数据的 Socket 异步操作对象
            private SocketAsyncEventArgs _socketAsyncSend;
    
            // 用于接收数据的 Socket 异步操作对象
            private SocketAsyncEventArgs _socketAsyncReceive;
    
            // 是否已发送过数据
            private bool _sent = false;
    
            private ManualResetEvent _signalSend = new ManualResetEvent(false);
    
            public UdpDemo()
            {
                InitializeComponent();
    
                this.Loaded += new RoutedEventHandler(UdpDemo_Loaded);
            }
    
            void UdpDemo_Loaded(object sender, RoutedEventArgs e)
            {
                // 初始化姓名和需要发送的默认文字
                txtName.Text = "匿名用户" + new Random().Next(0, 9999).ToString().PadLeft(4, '0');
                txtInput.Text = "hi";
    
                // 实例化 Socket
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    
    
                // 实例化 SocketAsyncEventArgs ,用于发送数据
                _socketAsyncSend = new SocketAsyncEventArgs();
                // 服务端的 EndPoint
                _socketAsyncSend.RemoteEndPoint = new DnsEndPoint("192.168.8.217", 3367);
                // 异步操作完成后执行的事件
                _socketAsyncSend.Completed += new EventHandler<SocketAsyncEventArgs>(_socketAsyncSend_Completed);
            }
    
            public void SendData()
            {
                byte[] payload = Encoding.UTF8.GetBytes(txtName.Text + "" + txtInput.Text);
                // 设置需要发送的数据的缓冲区
                _socketAsyncSend.SetBuffer(payload, 0, payload.Length);
    
                _signalSend.Reset(); // 无信号
    
                // 异步地向服务端发送信息(SendToAsync - UDP;SendAsync - TCP)
                _socket.SendToAsync(_socketAsyncSend);
               
                _signalSend.WaitOne(3000); // 阻塞
            }
    
            void _socketAsyncSend_Completed(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError != SocketError.Success)
                {
                    OutputMessage(e.SocketError.ToString());
                }
    
                _signalSend.Set(); // 有信号
    
                if (!_sent)
                {
                    _sent = true;
                    // 注:只有发送过数据,才能接收数据,否则 ReceiveFromAsync() 时会出现异常
                    ReceiveData();
                }
            }
    
            // 接收信息
            public void ReceiveData()
            {
                // 实例化 SocketAsyncEventArgs,并指定端口,以接收数据
                _socketAsyncReceive = new SocketAsyncEventArgs();
                _socketAsyncReceive.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 3367);
    
                // 设置接收数据的缓冲区,udp 报文(Datagram)的最大长度为 65535(包括报文头)
                _socketAsyncReceive.SetBuffer(new Byte[65535], 0, 65535);
                _socketAsyncReceive.Completed += new EventHandler<SocketAsyncEventArgs>(_socketAsyncReceive_Completed);
    
                // 异步地接收数据(ReceiveFromAsync - UDP;ReceiveAsync - TCP)
                _socket.ReceiveFromAsync(_socketAsyncReceive);
            }
    
            void _socketAsyncReceive_Completed(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    // 接收数据成功,将接收到的数据转换成字符串,并去掉两头的空字节
                    var response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                    response = response.Trim('\0');
    
                    OutputMessage(response);
                }
                else
                {
                    OutputMessage(e.SocketError.ToString());
                }
    
                // 继续异步地接收数据
                _socket.ReceiveFromAsync(e);
            }
    
            private void OutputMessage(string data)
            {
                // 在聊天文本框中输出指定的信息,并将滚动条滚到底部
                this.Dispatcher.BeginInvoke(
                    delegate
                    {
                        txtChat.Text += data + "\r\n";
                        svChat.ScrollToVerticalOffset(txtChat.ActualHeight - svChat.Height);
                    }
                );
            }
    
            private void btnSend_Click(object sender, RoutedEventArgs e)
            {
                SendData();
            }
    
            private void txtInput_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Enter)
                {
                    SendData();
                    this.Focus();
                }
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    ubuntu安装pgAdmin 4
    python 读取文件
    byobu copy
    vim快捷键汇总
    python 停止线程
    python执行外部命令并获取输出
    gevent mysql
    python类型转换
    量化交易
    Java集合:HashMap底层实现和原理(源码解析)
  • 原文地址:https://www.cnblogs.com/webabcd/p/2688170.html
Copyright © 2020-2023  润新知