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、心跳包。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持硕编程。