博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在Silverlight中使用Socket进行通信(3)简单的文本聊天工具
阅读量:6407 次
发布时间:2019-06-23

本文共 5652 字,大约阅读时间需要 18 分钟。

在上一篇的基础上,晚上我又尝试了一下做个聊天工具,有个定时取消息的过程解决不好,明天再研究一下,在这个文本聊天的基础上,稍加扩展就可以进行视频聊天了,下一篇将会做silverlight视频聊天的DEMO.

整体效果是

    

 

还是从服务端说起,服务端做中转消息用,为了模拟聊天情景,服务端简单写了一个实体用来缓存聊天内容 

代码
public
 
class
 UserSocket 
    { 
        
public
 
string
 UserName { 
set
get
; } 
        
public
 
string
 PartnerName { 
set
get
; }         
        
public
 
string
 Message { 
set
get
; } 
        
public
 DateTime StoreTime { 
set
get
; } 
    }

  

然后在主程序中声明一个List<UserSocket>对象存储聊天内容。

static List<UserSocket> listUserSocket = new List<UserSocket>();

当聊天双方给对方发送消息时,可以通过预先设定的字符串格式,比如采用 - 来将发送者,接受者,聊天内容组合起来发送到服务器进行解析和存储。

 代码

byte
[] bytData 
=
 
new
 
byte
[
1024
]; 
                
int
 receivedLength 
=
 client.Receive(bytData); 
                
string
 strReceive 
=
 System.Text.Encoding.UTF8.GetString(bytData, 
0
, receivedLength); 
                listUserSocket.Add(
new
 UserSocket() 
                { UserName 
=
 strReceive.Split(
'
-
'
)[
0
], 
                    PartnerName 
=
 strReceive.Split(
'
-
'
)[
1
], 
                    Message 
=
 strReceive.Split(
'
-
'
)[
2
], 
                    StoreTime
=
DateTime.Now });

 

 当客户端A定时来服务器请求发给自己的消息时,服务器就会在listUserSocket中查找到发送给A的消息并清除此消息。

 代码

UserSocket userSocket 
=
 listUserSocket.Where(m 
=>
 m.PartnerName 
==
 strReceive.Split(
'
-
'
)[
0
]).FirstOrDefault(); 
                listUserSocket.RemoveAll(m 
=>
 m.PartnerName 
==
 strReceive.Split(
'
-
'
)[
0
]);

 

 关键代码:

由于silverlight中没有提供监听socket请求的方法,只能作为客户端跟服务器进行交互,所以在客户端我们可以预先定义一个Socket

 

private
  Socket clientSocket 
=
 
null
;  

 及远程通信的IP和端口 

private
 
const
 
string
 SERVER_IP 
=
 
"
127.0.0.1
"
        
private
 
const
 
int
 SERVER_PORT 
=
 
4530
;

 我们可以为这个clientSocket建立起连接 

代码
clientSocket 
=
 
new
 Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
            SocketAsyncEventArgs socketEventArg 
=
 
new
 SocketAsyncEventArgs() 
            { 
                RemoteEndPoint 
=
 
new
 IPEndPoint(IPAddress.Parse(SERVER_IP), SERVER_PORT) 
            }; 
            socketEventArg.Completed 
+=
new
 EventHandler
<
SocketAsyncEventArgs
>
(socketEventArg_Completed); 
            clientSocket.ConnectAsync(socketEventArg);

 

鉴于sl的事件处理是异步的,所以 

代码
//
 连接成功后 开始发送 
        
void
 socketEventArg_Completed(
object
 sender, SocketAsyncEventArgs e) 
        { 
            
if
 (e.SocketError 
==
 SocketError.Success) 
            { 
                
//
AddText("已连接服务器!"); 
                
string
 strSend 
=
 USERNAME
+
"
-
"
+
PARTNERNAME
+
"
-
"
+
MESSAGE; 
                
byte
[] bytSend 
=
 Encoding.UTF8.GetBytes(strSend); 
                SocketAsyncEventArgs socketArg 
=
 
new
 SocketAsyncEventArgs(); 
                socketArg.Completed 
+=
 
new
 EventHandler
<
SocketAsyncEventArgs
>
(socketArg_Completed); 
                socketArg.SetBuffer(bytSend, 
0
, bytSend.Length); 
                clientSocket.SendAsync(socketArg); 
                
//
AddText("向服务器发送信息...");                
            }            
        }

  

当发送成功后,就可以向服务器取消息啦 

代码
void
 socketArg_Completed(
object
 sender, SocketAsyncEventArgs e) 
        { 
             
//
发送成功 
            
if
 (e.SocketError 
==
 SocketError.Success) 
            { 
                AddText(
"
已经将自己的IP和聊天对象发送到服务器
"
); 
            } 
            timer 
=
 
new
 Timer(
new
 TimerCallback(StartReceive), 
null
500
1000
);            
        }

  

定时取消息的方法,也是异步的 

代码
void
 StartReceive(
object
 o) 
        { 
            
byte
[] byteReceive
=
new
 
byte
[
102400
]; 
            SocketAsyncEventArgs socketReceiveArg 
=
 
new
 SocketAsyncEventArgs(); 
            socketReceiveArg.Completed 
+=
 
new
 EventHandler
<
SocketAsyncEventArgs
>
(socketReceiveArg_Completed); 
            socketReceiveArg.SetBuffer(byteReceive, 
0
, byteReceive.Length); 
            clientSocket.ReceiveAsync(socketReceiveArg); 
        } 
        
void
 socketReceiveArg_Completed(
object
 sender, SocketAsyncEventArgs e) 
        { 
            
if
 (e.SocketError 
==
 SocketError.Success) 
            { 
                
byte
[] byteReceive 
=
 e.Buffer; 
                
string
 strText 
=
 System.Text.Encoding.UTF8.GetString(byteReceive, 
0
, byteReceive.Length); 
                AddText(
"
成功接收到服务器回传的消息
"
 
+
 strText); 
            } 
        } 

 可以看到,从连接到发送,再到接收,我们用的是一个socket实例来完成的,也就是说在silverlight中只需要连接一次socket就可以顺利进行后续操作了。

服务端的监听

服务端的监听socket 跟客户端的不同,监听是一个socket实例,发送和接收则是另外一个代表客户端的实例。

首先还是需要指定监听IP和端口及使用的Socket

 

private
 
const
 
string
 SERVER_IP 
=
 
"
127.0.0.1
"
        
private
 
const
 
int
 SERVER_PORT 
=
 
4530
        
static
 Socket listener;

  

同样,也需要进行策略文件的验证 

代码
#region
 Start The Policy Server 
                PolicySocketServer StartPolicyServer 
=
 
new
 PolicySocketServer(); 
                Thread th 
=
 
new
 Thread(
new
 ThreadStart(StartPolicyServer.StartSocketServer)); 
                th.IsBackground 
=
 
true
                th.Start(); 
                
#endregion

 

 然后开始监听 

代码
IPEndPoint localEndPoint 
=
 
new
 IPEndPoint(IPAddress.Parse(SERVER_IP), SERVER_PORT); 
                listener 
=
 
new
 Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
                listener.Bind(localEndPoint); 
                listener.Listen(
-
1
); 
                Console.WriteLine(
"
等待客户端连接...
"
); 
                
while
 (
true
                { 
                    Socket clientSocket 
=
 listener.Accept(); 
                    
if
 (clientSocket.Connected) 
                    {                     
                        Thread myThread 
=
 
new
 Thread(
new
 ParameterizedThreadStart(SocketThread)); 
                        myThread.Start(clientSocket); 
                    } 
                } 

 

 当监听到有客户端连接时,就另外开启线程进行处理,这个操作同时也确定了需要多个socket实例进行应答。 

代码
static
 
void
 SocketThread(
object
 clientSocket)   
        { 
            
try
 
            { 
                Socket client 
=
 (Socket)clientSocket; 
                IPEndPoint address 
=
 (IPEndPoint)client.RemoteEndPoint; 
                
byte
[] bytData 
=
 
new
 
byte
[
1024
]; 
                
int
 receivedLength 
=
 client.Receive(bytData); 
                
string
 strReceive 
=
 System.Text.Encoding.UTF8.GetString(bytData, 
0
, receivedLength); 
                listUserSocket.Add(
new
 UserSocket() 
                { UserName 
=
 strReceive.Split(
'
-
'
)[
0
], 
                    PartnerName 
=
 strReceive.Split(
'
-
'
)[
1
], 
                    Message 
=
 strReceive.Split(
'
-
'
)[
2
], 
                    StoreTime
=
DateTime.Now }); 
                Console.WriteLine(
"
"
 
+
 strReceive.Split(
'
-
'
)[
0
+
 
"
】通过【
"
 
+
 address.Address.ToString() 
+
 
"
:
"
 
+
 address.Port.ToString() 
+
 
"
】登录了服务器,并给【
"
 
+
 strReceive.Split(
'
-
'
)[
1
+
 
"
】留言如下:
"
); 
                Console.WriteLine(strReceive.Split(
'
-
'
)[
2
]
+
"
,当前服务器消息数量【:
"
+
listUserSocket.Count.ToString()
+
"
"
); 
                UserSocket userSocket 
=
 listUserSocket.Where(m 
=>
 m.PartnerName 
==
 strReceive.Split(
'
-
'
)[
0
]).FirstOrDefault(); 
                listUserSocket.RemoveAll(m 
=>
 m.PartnerName 
==
 strReceive.Split(
'
-
'
)[
0
]); 
                
if
 (userSocket 
!=
 
null
                { 
                    client.Send(System.Text.Encoding.UTF8.GetBytes(userSocket.Message)); 
                    Console.WriteLine(
"
"
 
+
 userSocket.PartnerName 
+
 
"
】取走了消息【
"
 
+
 userSocket.Message 
+
 
"
】,当前服务器消息数量【:
"
+
listUserSocket.Count.ToString()
+
"
"
); 
                } 
            } 
            
catch
 
            {   } 
        } 
     本文转自wengyuli 51CTO博客,原文链接:http://blog.51cto.com/wengyuli/587562,如需转载请自行联系原作者
你可能感兴趣的文章
Linux Foundation(笔记)
查看>>
Java学习第二十五天
查看>>
vim配置
查看>>
ubuntu 把软件源修改为国内源和更新
查看>>
随机产生四则运算,导入导出文件
查看>>
位运算符
查看>>
winform自定义控件
查看>>
C#编码好习惯
查看>>
避其锋芒,侧翼出击。——司马亮创业回忆录(一)
查看>>
scope
查看>>
一起谈.NET技术,晚绑定场景下对象属性赋值和取值可以不需要PropertyInfo
查看>>
一起谈.NET技术,.Net Framework源代码中的模式之Prototype(原型模式)
查看>>
[shell 命令] find 查找文件
查看>>
windows下启动mysql服务的命令行启动和手动启动方法
查看>>
VTK三维点集轮廓凸包提取
查看>>
【概率论与数理统计】小结9-3 - 区间估计
查看>>
Golang性能调优入门
查看>>
sqlloader外部表
查看>>
golang笔记——数组与切片
查看>>
屏蔽可忽略的js脚本错误
查看>>