C#之Socket客户端全过程
c#之socket客户端全过程
c#开发socket客户端
我们先新建一个类:socketclientasync。
注意点:
1、由于socket通讯是发送到缓存区内的数据是覆盖,而不是新的,也就是说如果我们第一次发送的内容是 byte[]{0x11,0x22};而第二次发送的内容是byte[]{0x22}。那么我们的服务端在第二次接受到的数据是byte[]{0x22,0x22}。
所以我们需要在socket.send(byte[] mes)方法里面声明
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; i++)
{
buffer[i] = 0x00;
}
起到的作用就是每次在发送新的内容到服务端的时候,会将所有的旧的内容替换掉;
2、关闭连接之前需要将通知服务端停止发送和接受,也就是
this.clientsocket.shutdown(socketshutdown.both);
中断套接字连接:通知服务器端或客户端停止接收和发送数据。
通知完成之后如果客户端还连接着再进行自己的连接断开
if (this.clientsocket.connected)
{
this.clientsocket.close();
}
3、具体类的代码见下图,可以直接使用
#region socketclient客户端
public class socketclientasync
{
#region 声明变量
public string ipadress;
public bool connected = false;
public socket clientsocket;
private ipendpoint hostendpoint;
private int flag = 0;
private autoresetevent autoconnectevent = new autoresetevent(false);
private socketasynceventargs lisntersocketasynceventargs;
public delegate void startlistehandler();
public event startlistehandler startlisten;
public delegate void receivemsghandler(byte[] info, int i);
public event receivemsghandler onmsgreceived;
private list<socketasynceventargs> s_lst = new list<socketasynceventargs>();
#endregion
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="i"></param>
public socketclientasync(string hostname, int port, int i)
{
flag = i;
ipadress = hostname;
ipaddress[] hostaddresses = dns.gethostaddresses(hostname);
this.hostendpoint = new ipendpoint(hostaddresses[hostaddresses.length - 1], port);
this.clientsocket = new socket(this.hostendpoint.addressfamily, sockettype.stream, protocoltype.tcp);
}
#endregion
#region 开始连接服务端
/// <summary>
/// 连接服务端
/// </summary>
/// <returns></returns>
private bool connect()
{
using (socketasynceventargs args = new socketasynceventargs())
{
args.usertoken = this.clientsocket;
args.remoteendpoint = this.hostendpoint;
args.completed += new eventhandler<socketasynceventargs>(this.onconnect);
this.clientsocket.connectasync(args);
bool flag = autoconnectevent.waitone(5000);
if (this.connected)
{
this.lisntersocketasynceventargs = new socketasynceventargs();
byte[] buffer = new byte[1024];
this.lisntersocketasynceventargs.usertoken = this.clientsocket;
this.lisntersocketasynceventargs.setbuffer(buffer, 0, buffer.length);
this.lisntersocketasynceventargs.completed += new eventhandler<socketasynceventargs>(this.onreceive);
this.startlisten();
return true;
}
return false;
}
}
#endregion
#region 判断有没有连接上服务端
/// <summary>
/// 判断有没有连接上
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void onconnect(object sender, socketasynceventargs e)
{
this.connected = (e.socketerror == socketerror.success);
autoconnectevent.set();
}
#endregion
#region 发送数据到服务端
/// <summary>
/// 发送
/// </summary>
/// <param name="mes"></param>
public void send(byte[] mes)
{
if (this.connected)
{
eventhandler<socketasynceventargs> handler = null;
//byte[] buffer = encoding.default.getbytes(mes);
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; i++)
{
buffer[i] = 0x00;
}
array.copy(mes, 0, buffer, 0, mes.length);
socketasynceventargs sendersocketasynceventargs = null;
lock (s_lst)
{
if (s_lst.count > 0)
{
sendersocketasynceventargs = s_lst[s_lst.count - 1];
s_lst.removeat(s_lst.count - 1);
}
}
if (sendersocketasynceventargs == null)
{
sendersocketasynceventargs = new socketasynceventargs();
sendersocketasynceventargs.usertoken = this.clientsocket;
sendersocketasynceventargs.remoteendpoint = this.clientsocket.remoteendpoint;
if (handler == null)
{
handler = delegate(object sender, socketasynceventargs _e)
{
lock (s_lst)
{
s_lst.add(sendersocketasynceventargs);
}
};
}
sendersocketasynceventargs.completed += handler;
}
sendersocketasynceventargs.setbuffer(buffer, 0, buffer.length);
this.clientsocket.sendasync(sendersocketasynceventargs);
}
else
{
this.connected = false;
}
}
#endregion
#region 监听服务端
/// <summary>
/// 监听服务端
/// </summary>
public void listen()
{
if (this.connected && this.clientsocket != null)
{
try
{
(lisntersocketasynceventargs.usertoken as socket).receiveasync(lisntersocketasynceventargs);
}
catch (exception)
{
}
}
}
#endregion
#region 断开服务端的连接
/// <summary>
/// 断开连接
/// </summary>
/// <returns></returns>
private int disconnect()
{
int res = 0;
try
{
this.clientsocket.shutdown(socketshutdown.both);
}
catch (exception)
{
}
try
{
this.clientsocket.close();
}
catch (exception)
{
}
this.connected = false;
return res;
}
#endregion
#region 数据接收
/// <summary>
/// 数据接受
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void onreceive(object sender, socketasynceventargs e)
{
if (e.bytestransferred == 0)
{
if (clientsocket.connected)
{
try
{
this.clientsocket.shutdown(socketshutdown.both);
}
catch (exception)
{
}
finally
{
if (this.clientsocket.connected)
{
this.clientsocket.close();
}
}
}
byte[] info = new byte[] { 0 };
this.onmsgreceived(info, flag);
}
else
{
byte[] buffer = new byte[e.bytestransferred];
buffer.blockcopy(e.buffer, 0, buffer, 0, e.bytestransferred);
this.onmsgreceived(buffer, flag);
listen();
}
}
#endregion
#region 建立连接服务端的方法
/// <summary>
/// 建立连接的方法
/// </summary>
/// <returns></returns>
public bool connectserver()
{
bool flag = false;
this.startlisten += new startlistehandler(socketclient_startlisten);
// this.onmsgreceived += new receivemsghandler(socketclient_onmsgreceived);
flag = this.connect();
if (!flag)
{
return flag;
}
return true;
}
#endregion
#region 关闭与服务端之间的连接
/// <summary>
/// 关闭连接的方法
/// </summary>
/// <returns></returns>
public int closelinkserver()
{
return this.disconnect();
}
#endregion
#region 监听方法
/// <summary>
/// 监听的方法
/// </summary>
private void socketclient_startlisten()
{
this.listen();
}
#endregion
#region idispose member
public void dispose()
{
if (this.clientsocket.connected)
{
this.clientsocket.close();
}
}
#endregion
#region 析构函数
~socketclientasync()
{
try
{
if (this.clientsocket.connected)
{
this.clientsocket.close();
}
}
catch
{
}
finally
{
}
}
#endregion
}
#endregion
4、然后就是类的调用了
//声明定义变量
private socketclientasync clientlink;//客户端连接对象
private string client_ip = "127.0.0.1";//服务端ip地址
private int client_port = 12345;//服务端监听的端口号
private thread client_td;//通讯内部使用线程
private bool clientlinkres = false;//服务器通讯状态标志
private bool threadcontinue = true;//线程轮询标志
private bool isonline = false;//是否在线标志
/// <summary>
/// 启动线程
/// </summary>
private void startserver()
{
client_td = new thread(linksocketserfunc);
client_td.start();
}
/// <summary>
/// 重连服务端线程
/// </summary>
private void linksocketserfunc()
{
object lockobj = new object();
int heartbeatcount = 0;
clientlink = new socketclientasync(client_ip, client_port, 0);
bool notfirstin = false;
while (threadcontinue)
{
try
{
if (!clientlinkres)
{
isonline = false;
if (notfirstin)
{
clientlink.closelinkserver();
clientlink = new socketclientasync(client_ip, client_port, 0);
}
notfirstin = true;
clientlink.onmsgreceived += new socketclientasync.receivemsghandler(client_onmsgreceived);//绑定接受到服务端消息的事件
clientlinkres = clientlink.connectserver();
}
else
{
//此处写通讯成功的逻辑处理
}
}
catch (exception ex)
{
clientlinkres = false;
system.diagnostics.debug.writeline(ex.tostring());
}
thread.sleep(1000);
}
}
/// <summary>
/// 接收消息处理
/// </summary>
/// <param name="info"></param>
/// <param name="num"></param>
private void client_onmsgreceived(byte[] info, int num)
{
try
{
clientheartbeat = 0;
if (info.length > 0 && info[0] != 0)//bcr连接错误no
{
//info为接受到服务器传过来的字节数组,需要进行什么样的逻辑处理在此书写便可
}
else
{
clientlinkres = false;
}
}
catch (exception ex)
{
system.diagnostics.debug.writeline(ex.tostring());
}
}
/// <summary>
/// 终止服务
/// </summary>
public void stopserver()
{
if (clientlinkres)
{
threadcontinue = false;
clientlink.closelinkserver();
clientlink.dispose();
}
}
这基本的socket客户端后台就写完了,可以直接复制使用,平时都是用这么去写socket客户端,分享出来,大家就可以直接使用了!
c#socket客户端异步实现
简易封装
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using system.net;
using system.net.sockets;
namespace dclient
{
public delegate void delegatemsg(object msg);
public class client
{
private static socket _clientsocket;
private static string _server;
private static int _port;
public static delegatemsg onconnect;
public static delegatemsg onsend;
public static delegatemsg onreceive;
public static delegatemsg onserverdown;
public static delegatemsg onerr;
public static void connect()
{
try
{
_server = system.configuration.configurationmanager.appsettings["serverip"];
_port = int.parse(system.configuration.configurationmanager.appsettings["serverport"]);
ipendpoint ip = new ipendpoint(ipaddress.parse(_server), _port);
_clientsocket = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp);
_clientsocket.beginconnect(ip, new asynccallback(connectcallback), _clientsocket);
}
catch (exception e)
{
throw e;
}
}
private static void connectcallback(iasyncresult iar)
{
socket client = (socket)iar.asyncstate;
try
{
client.endconnect(iar);
onconnect("已连接");
}
catch (socketexception e)
{
if (e.errorcode == 10061)
{
onerr("服务器程序未运行或服务器端口未开放");
}
else
{
onerr(e.message);
}
}
finally
{
}
}
public static void send(string msg)
{
if (_clientsocket == null || msg == string.empty) return;
msg += "\r\n";
byte[] data = encoding.utf8.getbytes(msg);
try
{
_clientsocket.beginsend(data, 0, data.length, socketflags.none, asyncresult =>
{
int length = _clientsocket.endsend(asyncresult);
onsend(string.format("客户端发送消息:{0}", msg));
}, null);
}
catch (exception e)
{
onerr(e.message);
}
}
public static void recive()
{
byte[] data = new byte[1024];
try
{
_clientsocket.beginreceive(data, 0, data.length, socketflags.none,
asyncresult =>
{
try
{
int length = _clientsocket.endreceive(asyncresult);
onreceive(string.format("收到服务器消息:长度:{1},{0}", encoding.utf8.getstring(data), length));
recive();
}
catch (socketexception e)
{
if (e.errorcode == 10054)
{
onserverdown("服务器已断线");
}
else
{
onerr(e.message);
}
}
}, null);
}
catch (exception ex)
{
onerr(ex.message);
}
}
}
}
使用
public partial class form1 : form
{
public form1()
{
initializecomponent();
client.onconnect += new delegatemsg(connect);
client.onsend += new delegatemsg(send);
client.onreceive += new delegatemsg(receive);
client.onserverdown += new delegatemsg(svrdown);
client.onerr += new delegatemsg(onerr);
}
private void form1_load(object sender, eventargs e)
{
client.connect();
}
private void connect(object msg)
{
system.diagnostics.debug.writeline(msg.tostring());
client.send("dalo 发送测试");
client.recive();
}
private void send(object msg)
{
system.diagnostics.debug.writeline(msg.tostring());
}
private void receive(object msg)
{
system.diagnostics.debug.writeline(msg.tostring());
}
private void svrdown(object msg)
{
system.diagnostics.debug.writeline(msg.tostring());
}
private void onerr(object msg)
{
system.diagnostics.debug.writeline(msg.tostring());
}
}
未实现的几个常用操作
1、接收服务器发送的大数据量的合包。
2、服务器断线后客户端自动检测并重连,需先将_clientsocket释放。
3、心跳包。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持硕编程。


