实现功能,能够随时发送数据,并且能够随时接收服务端发送过来的数据,能够判断服务端或端口网络的连接状态,随时查看与服务器通讯是否通畅。
可以使用VS创建一个用户控件或创建一个类,来控制Socket通讯,代码成熟,建议做成用户控件,这样可以随时拖拽控件,写事件什么的都方便。
在写Socket客户端之前,要知道Socket客户端接收数据,使用 的线程循环的方式,有数据接收到的时候,触发消息事件,在断开事件处理时,能够触发断开连接事件,这时要定义几个委托,承载事件的触发。
public delegate void ReceiveBuffer(byte[] buffer);//收到消息时,传递消息Buffer的事件。
public delegate void HostDisconnectionEvent();//断开连接时,触发的事件。
我在使用的时候,习惯将委托单独放在一个.cs文件当,定义为委托事件类:DelegateEvent.cs
还要考虑到,在Socket接收消息时,需要使用线程,那么在触发收到消息的事件后,如果需要修改界面上的参数或值,需要做控件的异步调用处理,这样处理起来太麻烦,而且处理不好,到时会有一堆的Bug,这是我在使用过程当中遇到的。那么有一没有办法不使用线程,让客户端循环接收消息呢?这时我想到了使用异步,最后又增加了一个异步收消息的委托:
public delegate void AsyncReceivedClient(object sender);//异步收到消息时的委托,如果整个类当中只有一个客户端连接,可以不带参数。
这时,委托类基本建完了,那么,这时需要定义代码了:
创建一个TCPClient类,当然,这个类和System.Net.Sockets下的类不同,为了区分,我定义的命名空间为:System.Net.Securate.TCP,下面是定义的事件和参数:
///
/// 收到消息事件
///
public ReceiveBuffer ReceiveComtemplate;
///
/// 主机断开连接事件
///
public HostDisconnectionEvent HostDisconnectedComtelplate;
private string _Address;
///
/// 获取或设置连接地址
///
public string Address
{
get { return _Address; }
set { _Address = value; }
}
private int _Port;
///
/// 获取或设置端口号
///
public int Port
{
get { return _Port; }
set { _Port = value; }
}
private Socket tcpClient;
///
/// 获取连接状态
///
public bool IsConnected
{
get {
if (tcpClient == null)
return false;
return tcpClient.Connected;
}
}
创建连接的启动事件,我写两种启动方式,一种是不带参的,一种是带参的,如下:
///
/// 打开连接
///
///
public bool Start()
{
return Start(_Address, _Port);
}
///
/// 打开连接
///
/// 连接地址
/// 连接端口号
///
public bool Start(string ip, int port)
{
try
{
_Address = ip;
_Port = port;
tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipaddress = IPAddress.Parse(_Address);
tcpClient.Connect(ipaddress, port);
if (tcpClient.Connected)
{
AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
rc.BeginInvoke(tcpClient, null, null);
}
return tcpClient.Connected;
}
catch (Exception ex)
{
return false;
}
}
需要注意的是:
AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
rc.BeginInvoke(tcpClient, null, null);
这两行,实现的是异步委托带参的调用,实现随时接收服务端发送过来的消息。
在客户端收消息时,需要判断服务端连接是否断开,在网上的介绍上,说使用socket.Poll(1, SelectMode.SelectRead)和socket.Available= 0来判断网络是否断开,但在实际上的使用当中,我使用第三方的服务端,使用这种方式,根本不能判断断开,后来我想,能不能开一个SocketCient,来判断服务端口是否正常,相当于telnet命令,在实际使用当中,还没遇到问题:
///
/// 接收消息
///
///
public void Receive(object o)
{
Socket s = o as Socket;
bool IsConnected = true;
while (s.Connected)
{
try
{
int res = s.Available;
if (res > 0)
{
byte[] xxxx = new byte[res];
int nRead = s.Receive(xxxx);
byte[] buffer = new byte[nRead];
Array.Copy(xxxx, 0, buffer, 0, nRead);
if (ReceiveComtemplate != null)
ReceiveComtemplate(buffer);
}
else
{
try
{
Socket testSocket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
testSocket.Connect(s.RemoteEndPoint);
if (!testSocket.Connected)
{
Stop();
IsConnected = false;
goto EndReceive;
}
else
{
testSocket.Shutdown(SocketShutdown.Both);
testSocket.Close();
}
}
catch (Exception ex)
{
Stop();
IsConnected = false;
goto EndReceive;
}
}
}
catch (Exception ex)
{
Stop();
IsConnected = false;
goto EndReceive;
}
Thread.Sleep(100);
}
EndReceive:
if (!IsConnected)
{
if (HostDisconnectedComtelplate != null)
HostDisconnectedComtelplate();
}
}
最后就是一个发送,一个停止,这个部分,基本和msdn上介绍的一样,没有什么特殊的处理:
///
/// 发送消息
///
/// 发送的数据
public void Send(byte[] buffer)
{
try
{
if (tcpClient.Connected)
{
tcpClient.Send(buffer);
}
}
catch { }
}
///
/// 停止
///
public void Stop()
{
try
{
//tcpClient.Client.Shutdown(SocketShutdown.Both);
//tcpClient.Close();
tcpClient.Shutdown(SocketShutdown.Both);
tcpClient.Close();
}
catch (Exception ex)
{ }
}
到这里基本上已经完成,完整代码如下,如果有不同看法或有更好的意见,欢迎在线留言:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace System.Net.Securate.TCP
{
public sealed class TCPClient
{
///
/// 收到消息事件
///
public ReceiveBuffer ReceiveComtemplate;
///
/// 主机断开连接事件
///
public HostDisconnectionEvent HostDisconnectedComtelplate;
private string _Address;
///
/// 获取或设置连接地址
///
public string Address
{
get { return _Address; }
set { _Address = value; }
}
private int _Port;
///
/// 获取或设置端口号
///
public int Port
{
get { return _Port; }
set { _Port = value; }
}
private Socket tcpClient;
///
/// 获取连接状态
///
public bool IsConnected
{
get {
if (tcpClient == null)
return false;
return tcpClient.Connected;
}
}
///
/// 打开连接
///
///
public bool Start()
{
return Start(_Address, _Port);
}
///
/// 打开连接
///
/// 连接地址
/// 连接端口号
///
public bool Start(string ip, int port)
{
try
{
_Address = ip;
_Port = port;
tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipaddress = IPAddress.Parse(_Address);
tcpClient.Connect(ipaddress, port);
if (tcpClient.Connected)
{
AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
rc.BeginInvoke(tcpClient, null, null);
}
return tcpClient.Connected;
}
catch (Exception ex)
{
return false;
}
}
///
/// 接收消息
///
///
public void Receive(object o)
{
Socket s = o as Socket;
bool IsConnected = true;
while (s.Connected)
{
try
{
int res = s.Available;
if (res > 0)
{
byte[] xxxx = new byte[res];
int nRead = s.Receive(xxxx);
byte[] buffer = new byte[nRead];
Array.Copy(xxxx, 0, buffer, 0, nRead);
if (ReceiveComtemplate != null)
ReceiveComtemplate(buffer);
}
else
{
try
{
Socket testSocket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
testSocket.Connect(s.RemoteEndPoint);
if (!testSocket.Connected)
{
Stop();
IsConnected = false;
goto EndReceive;
}
else
{
testSocket.Shutdown(SocketShutdown.Both);
testSocket.Close();
}
}
catch (Exception ex)
{
Stop();
IsConnected = false;
goto EndReceive;
}
}
}
catch (Exception ex)
{
Stop();
IsConnected = false;
goto EndReceive;
}
Thread.Sleep(100);
}
EndReceive:
if (!IsConnected)
{
if (HostDisconnectedComtelplate != null)
HostDisconnectedComtelplate();
}
}
///
/// 发送消息
///
/// 发送的数据
public void Send(byte[] buffer)
{
try
{
if (tcpClient.Connected)
{
tcpClient.Send(buffer);
}
}
catch { }
}
///
/// 停止
///
public void Stop()
{
try
{
//tcpClient.Client.Shutdown(SocketShutdown.Both);
//tcpClient.Close();
tcpClient.Shutdown(SocketShutdown.Both);
tcpClient.Close();
}
catch (Exception ex)
{ }
}
}
}