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

时间:2022-03-20 23:55:40

原文:与众不同 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();
// 客户端终结点
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, , 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(, ).ToString().PadLeft(, '');
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", );
// 异步操作完成后执行的事件
_socketAsyncSend.Completed += new EventHandler<SocketAsyncEventArgs>(_socketAsyncSend_Completed);
} public void SendData()
{
byte[] payload = Encoding.UTF8.GetBytes(txtName.Text + ":" + txtInput.Text);
// 设置需要发送的数据的缓冲区
_socketAsyncSend.SetBuffer(payload, , payload.Length); _signalSend.Reset(); // 无信号 // 异步地向服务端发送信息(SendToAsync - UDP;SendAsync - TCP)
_socket.SendToAsync(_socketAsyncSend); _signalSend.WaitOne(); // 阻塞
} 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, ); // 设置接收数据的缓冲区,udp 报文(Datagram)的最大长度为 65535(包括报文头)
_socketAsyncReceive.SetBuffer(new Byte[], , );
_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
[源码下载]

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

  1. 与众不同 windows phone &lpar;30&rpar; - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  2. Python编写基于socket的非阻塞多人聊天室程序(单线程&多线程)

    前置知识:socket非阻塞函数(socket.setblocking(False)),简单多线程编程 代码示例: 1. 单线程非阻塞版本: 服务端: #!/usr/bin/env python # ...

  3. 基于tcp和多线程的多人聊天室-C语言

    之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...

  4. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  5. C 基于UDP实现一个简易的聊天室

    引言 本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深 对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少 ...

  6. 与众不同 windows phone &lpar;33&rpar; - Communication(通信)之源特定组播 SSM(Source Specific Multicast)

    原文:与众不同 windows phone (33) - Communication(通信)之源特定组播 SSM(Source Specific Multicast) [索引页][源码下载] 与众不同 ...

  7. 与众不同 windows phone &lpar;32&rpar; - Communication(通信)之任意源组播 ASM(Any Source Multicast)

    原文:与众不同 windows phone (32) - Communication(通信)之任意源组播 ASM(Any Source Multicast) [索引页][源码下载] 与众不同 wind ...

  8. 与众不同 windows phone &lpar;29&rpar; - Communication(通信)之与 OData 服务通信

    原文:与众不同 windows phone (29) - Communication(通信)之与 OData 服务通信 [索引页][源码下载] 与众不同 windows phone (29) - Co ...

  9. 与众不同 windows phone &lpar;38&rpar; - 8&period;0 关联启动&colon; 使用外部程序打开一个文件或URI&comma; 关联指定的文件类型或协议

    [源码下载] 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议 作者:webabcd 介绍与众不同 windows ...

随机推荐

  1. &lbrack;nRF51822&rsqb; 12、基础实验代码解析大全 &&num;183&semi; 实验19 - PWM

    一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...

  2. HtmlAgilityPack 删除script、style以及注释标签

    foreach(var script in doc.DocumentNode.Descendants("script").ToArray()) script.Remove(); f ...

  3. xml文件的生成与解析

    生成方法一:同事StringBuffer类对xml文件格式解析写入 package com.steel_rocky.xml; import android.app.Activity; import a ...

  4. angularJs:双向数据绑定

    示例1 <!DOCTYPE html> <html ng-app> <head> <meta charset="UTF-8" /> ...

  5. Visual Studio 2012 离线升级包的制作

    通过CMD执行“VS2012.3.exe/layout”命令,就可以把在线升级的文件保存到本地,这样一来,只要把下载出来的文件打包上传,然后分享出去,所谓的“VS2012 Update 3 离线升级包 ...

  6. UDP通讯协议

    常见的通讯协议有udp和tcp. 先来简单了解一下这两个协议各自的特点: UDP: --将数据及源.目的封装在数据包中,不需要建立连接: --每个数据包的大小限制在64k以内: --因无连接,是不可靠 ...

  7. Mac 如何优雅的使用Microsoft office

    近期要使用文档编辑,但是发现mac下的pages实在不好用,或者说是不习惯,想安装个office  发现官方的office 都基本上要收费,网上的多数都要激活.实在没办法(没钱),看看WPS ,结果w ...

  8. curl 向远程服务器传输file文件

    public function upload(){ //获取上传文件信息,文件名称以自己实际上传文件名称为准 $fileinfo = $_FILE['filename']; //请求参数,依据商户自己 ...

  9. &lbrack;转&rsqb; 又踩到了crontab的老坑,特意记录下。

    http://xiachaofeng.iteye.com/blog/1405184 今天遇见一个问题,crontab的定时任务不能自动执行,但是手动执行脚本一直能成功.查到最后,发现是脚本里用了系统的 ...

  10. &dollar; each&lpar;&rpar; 小结

    each()方法能使DOM循环结构简洁,不容易出错.each()函数封装了十分强大的遍历功能,使用也很方便,它可以遍历一维数组.多维数组.DOM, JSON 等等在javaScript开发过程中使用$ ...