上接稳扎稳打Silverlight(24) - 2.0通信之Socket, 开发一个多人聊天室

上接稳扎稳打Silverlight(24) - 2.0通信之Socket, 开发一个多人聊天室,第1张

概述    Main.cs 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; usin     Main.cs

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 SocketServer

{

         public partial class Main : Form

        {

                SynchronizationContext _syncContext;


                System.Timers.Timer _timer;


                 // 信息结束符,用于判断是否完整地读取了用户发送的信息(要与客户端的信息结束符相对应)

                 private string _endMarker = "^";


                 // 服务端监听的 socket

                 private Socket _Listener;


                 // 实例化 ManualresetEvent, 设置其初始状态为非终止状态(可入状态)

                 private ManualresetEvent _connectDone = new ManualresetEvent( false);


                 // 客户端 Socket 列表

                 private List<ClIEntSocketPacket> _clIEntList = new List<ClIEntSocketPacket>();


                 public Main()

                {

                        InitializeComponent();


                         // UI 线程

                        _syncContext = SynchronizationContext.Current;


                         // 启动后台线程去运行 Socket 服务

                        Thread thread = new Thread( new ThreadStart(StartupSocketServer));

                        thread.IsBackground = true;

                        thread.Start();

                }


                 private voID StartupSocketServer()

                {

                         // 每 10 秒运行一次计时器所指定的方法

                        _timer = new System.Timers.Timer();

                        _timer.Interval = 10000d;

                        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);

                        _timer.Start();


                         // 初始化 socket , 然后与端口绑定, 然后对端口进行监听

                        _Listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

                        _Listener.Bind( new IPEndPoint(IPAddress.Any,4518)); // Silverlight 2.0 使用 Socket 只能连接 4502-4534 端口

                        _Listener.Listen(100);



                         while ( true)

                        {

                                 // 重置 ManualresetEvent,由此线程来控制 ManualresetEvent,其它到这里来的线程请等待

                                 // 为求简单易懂,本例实际上只有主线程会在这里循环运行

                                _connectDone.reset();


                                 // 开始接受客户端传入的连接

                                _Listener.BeginAccept( new AsyncCallback(OnClIEntConnect),null);


                                 // 阻止当前线程,直到当前 ManualresetEvent 调用 Set 发出继续信号

                                _connectDone.WaitOne();

                        }

                }


                 private voID _timer_Elapsed( object sender,System.Timers.ElapsedEventArgs e)

                {

                         // 每 10 秒给所有连入的客户端发送一次消息

                        SendData( string.Format( "webabcd 对所有人说:大家好! 【信息来自服务端 {0}】",DateTime.Now.ToString( "hh:mm:ss")));

                }


                 private voID OnClIEntConnect(IAsyncResult async)

                {

                         // 当前 ManualresetEvent 调用 Set 以发出继续信号,从而允许继续执行一个或多个等待线程

                        _connectDone.Set();


                        ClIEntSocketPacket clIEnt = new ClIEntSocketPacket();

                         // 完成接受客户端传入的连接的这个异步 *** 作,并返回客户端连入的 socket

                        clIEnt.socket = _Listener.EndAccept(async);


                         // 将客户端连入的 Socket 放进客户端 Socket 列表

                        _clIEntList.Add(clIEnt);



                        SendData( "一个新的客户端已经成功连入服务器。。。 【信息来自服务端】");



                         try

                        {

                                 // 开始接收客户端传入的数据

                                clIEnt.socket.BeginReceive(clIEnt.Buffer,clIEnt.Buffer.Length,SocketFlags.None,new AsyncCallback(OnDataReceived),clIEnt);

                        }

                         catch (SocketException ex)

                        {

                                 // 处理异常

                                HandleException(clIEnt,ex);

                        }

                }


                 private voID OnDataReceived(IAsyncResult async)

                {

                        ClIEntSocketPacket clIEnt = async.AsyncState as ClIEntSocketPacket;


                         int count = 0;


                         try

                        {

                                 // 完成接收数据的这个异步 *** 作,并返回接收的字节数

                                 if (clIEnt.socket.Connected)

                                        count = clIEnt.socket.EndReceive(async);

                        }

                         catch (SocketException ex)

                        {

                                HandleException(clIEnt,ex);

                        }


                         // 把接收到的数据添加进收到的字节集合内

                         // 本例采用UTF8编码,中文占用3字节,英文占用1字节,缓冲区为32字节

                         // 所以如果直接把当前缓冲区转成字符串的话可能会出现乱码,所以要等接收完用户发送的全部信息后再转成字符串

                         foreach ( byte b in clIEnt.Buffer.Take(count))

                        {

                                 if (b == 0) continue; // 如果是空字节则不做处理


                                clIEnt.ReceivedByte.Add(b);

                        }


                         // 把当前接收到的数据转换为字符串。用于判断是否包含自定义的结束符

                         string receivedString = UTF8EnCoding.UTF8.GetString(clIEnt.Buffer,count);


                         // 如果该 Socket 在网络缓冲区中没有排队的数据 并且 接收到的数据中有自定义的结束符时

                         if (clIEnt.socket.Connected && clIEnt.socket.Available == 0 && receivedString.Contains(_endMarker))

                        {

                                 // 把收到的字节集合转换成字符串(去掉自定义结束符)

                                 // 然后清除掉字节集合中的内容,以准备接收用户发送的下一条信息

                                 string content = UTF8EnCoding.UTF8.GetString(clIEnt.ReceivedByte.ToArray());

                                content = content.Replace(_endMarker,"");

                                clIEnt.ReceivedByte.Clear();


                                 // 发送数据到所有连入的客户端,并在服务端做记录

                                SendData(content);

                                _syncContext.Post(ResultCallback,content);

                        }


                         try

                        {

                                 // 继续开始接收客户端传入的数据

                                 if (clIEnt.socket.Connected)

                                        clIEnt.socket.BeginReceive(clIEnt.Buffer,clIEnt);

                        }

                         catch (SocketException ex)

                        {

                                HandleException(clIEnt,ex);

                        }

                }


                 /// <summary>

                 /// 发送数据到所有连入的客户端

                 /// </summary>

                 /// <param name="data">需要发送的数据</param>

                 private voID SendData( string data)

                {

                         byte[] byteData = UTF8EnCoding.UTF8.GetBytes(data);


                         foreach (ClIEntSocketPacket clIEnt in _clIEntList)

                        {

                                 if (clIEnt.socket.Connected)

                                {

                                         try

                                        {

                                                 // 如果某客户端 Socket 是连接状态,则向其发送数据

                                                clIEnt.socket.BeginSend(byteData,byteData.Length,new AsyncCallback(OnDataSent),clIEnt);

                                        }

                                         catch (SocketException ex)

                                        {

                                                HandleException(clIEnt,ex);

                                        }

                                }

                                 else    

                                {

                                         // 某 Socket 断开了连接的话则将其关闭,并将其清除出客户端 Socket 列表

                                         // 也就是说每次向所有客户端发送消息的时候,都会从客户端 Socket 集合中清除掉已经关闭了连接的 Socket

                                        clIEnt.socket.Close();

                                        _clIEntList.Remove(clIEnt);

                                }

                        }

                }


                 private voID OnDataSent(IAsyncResult async)

                {

                        ClIEntSocketPacket clIEnt = async.AsyncState as ClIEntSocketPacket;


                         try

                        {

                                 // 完成将信息发送到客户端的这个异步 *** 作

                                 if (clIEnt.socket.Connected)

                                        clIEnt.socket.EndSend(async);

                        }

                         catch (SocketException ex)

                        {

                                HandleException(clIEnt,ex);

                        }

                }


                 /// <summary>

                 /// 处理 SocketException 异常

                 /// </summary>

                 /// <param name="clIEnt">导致异常的 ClIEntSocketPacket</param>

                 /// <param name="ex">SocketException</param>

                 private voID HandleException(ClIEntSocketPacket clIEnt,SocketException ex)

                {

                         // 在服务端记录异常信息,关闭导致异常的 Socket,并将其清除出客户端 Socket 列表

                        _syncContext.Post(ResultCallback,clIEnt.socket.RemoteEndPoint.ToString() + " - " + ex.Message);

                        clIEnt.socket.Close();

                        _clIEntList.Remove(clIEnt);

                }


                 private voID ResultCallback( object result)

                {

                         // 输出相关信息

                        txtMsg.Text += result.ToString() + "\r\n";

                }

        }

}     3、Socket客户端(聊天室的客户端)
SocketClIEnt.xaml
<UserControl x:Class="Silverlight20.Communication.socketClIEnt"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <StackPanel HorizontalAlignment="left" WIDth="600" margin="5" Background="Gray">

                <ScrollVIEwer x:name="scrollChat" Height="400" VerticalScrollbarVisibility="auto" Background="White" margin="10">
                        <TextBlock x:name="txtChat" textwrapPing="Wrap" />
                </ScrollVIEwer>

                <StackPanel OrIEntation="Horizontal" margin="5">
                        <TextBox x:name="txtname" margin="5" WIDth="100" />
                        <TextBox x:name="txtinput" margin="5" WIDth="400" KeyDown="txtinput_KeyDown" />
                        <button x:name="btnSend" margin="5" WIDth="60" Content="Send" Click="btnSend_Click"/>
                </StackPanel>

        </StackPanel>
</UserControl>   SocketClIEnt.xaml.cs

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 System.Net.sockets;

using System.Text;


namespace Silverlight20.Communication

{

         public partial class SocketClIEnt : UserControl

        {

                 // 信息结束符,用于判断是否完整地读取了用户发送的信息(要与服务端的信息结束符相对应)

                 private string _endMarker = "^";


                 // 客户端 Socket

                 private Socket _socket;


                 // Socket 异步 *** 作对象

                 private socketasynceventargs _sendEventArgs;


                 public SocketClIEnt()

                {

                        InitializeComponent();


                         this.Loaded += new RoutedEventHandler(Page_Loaded);

                }


                 voID Page_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,ProtocolType.Tcp);


                         // 实例化 socketasynceventargs ,用于对 Socket 做异步 *** 作,很方便

                        socketasynceventargs args = new socketasynceventargs();

                         // 服务器的 EndPoint

                        args.RemoteEndPoint = new DnsEndPoint( "wanglei-pc",4518);

                         // 异步 *** 作完成后执行的事件

                        args.Completed += new EventHandler<socketasynceventargs>(OnSocketConnectCompleted);


                         // 异步连接服务端

                        _socket.ConnectAsync(args);

                }


                 private voID OnSocketConnectCompleted( object sender,socketasynceventargs e)

                {

                         // 设置数据缓冲区

                         byte[] response = new byte[1024];

                        e.SetBuffer(response,response.Length);


                         // 修改 socketasynceventargs 对象的异步 *** 作完成后需要执行的事件

                        e.Completed -= new EventHandler<socketasynceventargs>(OnSocketConnectCompleted);

                        e.Completed += new EventHandler<socketasynceventargs>(OnSocketReceiveCompleted);


                         // 异步地从服务端 Socket 接收数据

                        _socket.ReceiveAsync(e);


                         // 构造一个 socketasynceventargs 对象,用于用户向服务端发送消息

                        _sendEventArgs = new socketasynceventargs();

                        _sendEventArgs.RemoteEndPoint = e.RemoteEndPoint;


                         string data = "";

                         if (!_socket.Connected)

                                data = "无法连接到服务器。。。请刷新后再试。。。";

                         else

                                data = "成功地连接上了服务器。。。";


                        WriteText(data);

                }


                 private voID OnSocketReceiveCompleted( object sender,socketasynceventargs e)

                {

                         try

                        {

                                 // 将接收到的数据转换为字符串

                                 string data = UTF8EnCoding.UTF8.GetString(e.Buffer,e.Offset,e.BytesTransferred);


                                WriteText(data);

                        }

                         catch (Exception ex)

                        {

                                WriteText(ex.ToString());

                        }


                         // 继续异步地从服务端 Socket 接收数据

                        _socket.ReceiveAsync(e);

                }


                 private voID WriteText( string data)

                {

                         // 在聊天文本框中输出指定的信息,并将滚动条滚到底部

                         this.dispatcher.BeginInvoke(

                                 delegate

                                {

                                        txtChat.Text += data + "\r\n";

                                        scrollChat.ScrollToVerticalOffset(txtChat.ActualHeight);

                                }

                        );

                }


                 private voID SendData()

                {

                         if (_socket.Connected)

                        {

                                 // 设置需要发送的数据的缓冲区

                                _sendEventArgs.BufferList =

                                         new List<ArraySegment< byte>>()    

                                        {    

                                                 new ArraySegment< byte>(UTF8EnCoding.UTF8.GetBytes(txtname.Text + ":" + txtinput.Text + _endMarker))    

                                        };


                                 // 异步地向服务端 Socket 发送消息

                                _socket.SendAsync(_sendEventArgs);

                        }

                         else

                        {

                                txtChat.Text += "无法连接到服务器。。。请刷新后再试。。。\r\n";

                                _socket.Close();

                        }


                        txtinput.Focus();

                        txtinput.Text = "";

                }


                 private voID btnSend_Click( object sender,RoutedEventArgs e)

                {

                        SendData();

                }


                 private voID txtinput_KeyDown( object sender,KeyEventArgs e)

                {

                         // 按了回车键就向服务端发送数据

                         if (e.Key == Key.Enter)

                                SendData();

                }

        }

}     OK
[源码下载]
总结

以上是内存溢出为你收集整理的上接稳扎稳打Silverlight(24) - 2.0通信之Socket, 开发一个多人聊天室全部内容,希望文章能够帮你解决上接稳扎稳打Silverlight(24) - 2.0通信之Socket, 开发一个多人聊天室所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1052295.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存