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

简介: 原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室[索引页][源码下载] 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 作者:webabcd介绍与众不同 windows phone 7.
原文: 与众不同 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
[源码下载]

目录
相关文章
|
6月前
|
存储 安全 固态存储
基于C#实现的支持文件传输的Socket聊天室
基于C#实现的支持文件传输的Socket聊天室
380 5
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
656 2
|
Ubuntu Linux Python
如何利用wsl-Ubuntu里conda用来给Windows的PyCharm开发
如何在WSL(Windows Subsystem for Linux)的Ubuntu环境中使用conda虚拟环境来为Windows上的PyCharm开发设置Python解释器。
2238 1
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
768 0
Linux C/C++之TCP / UDP通信
|
网络协议 Linux 网络性能优化
Linux基础-socket详解、TCP/UDP
综上所述,Linux下的Socket编程是网络通信的重要组成部分,通过灵活运用TCP和UDP协议,开发者能够构建出满足不同需求的网络应用程序。掌握这些基础知识,是进行更复杂网络编程任务的基石。
552 1
|
Linux Apache C++
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
该文介绍了如何在Windows环境下为FFmpeg集成SRT协议支持库libsrt。首先,需要安装Perl和Nasm,然后编译OpenSSL。接着,下载libsrt源码并使用CMake配置,生成VS工程并编译生成srt.dll和srt.lib。最后,将编译出的库文件和头文件按照特定目录结构放置,并更新环境变量,重新配置启用libsrt的FFmpeg并进行编译安装。该过程有助于优化直播推流的性能,减少卡顿问题。
589 2
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
|
C语言
C语言 网络编程(七)UDP通信创建流程
本文档详细介绍了使用 UDP 协议进行通信的过程,包括创建套接字、发送与接收消息等关键步骤。首先,通过 `socket()` 函数创建套接字,并设置相应的参数。接着,使用 `sendto()` 函数向指定地址发送数据。为了绑定地址,需要调用 `bind()` 函数。接收端则通过 `recvfrom()` 函数接收数据并获取发送方的地址信息。文档还提供了完整的代码示例,展示了如何实现 UDP 的发送端和服务端功能。
|
监控 关系型数据库 MySQL
PowerShell 脚本编写 :自动化Windows 开发工作流程
PowerShell 脚本编写 :自动化Windows 开发工作流程
655 0
|
存储 安全 程序员
Windows任务管理器开发原理与实现
Windows任务管理器开发原理与实现
|
网络协议 网络架构
【网络编程入门】TCP与UDP通信实战:从零构建服务器与客户端对话(附简易源码,新手友好!)
在了解他们之前我们首先要知道网络模型,它分为两种,一种是OSI,一种是TCP/IP,当然他们的模型图是不同的,如下
517 1