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、心跳包。

 

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持硕编程

下一节:c#实现上位机与欧姆龙plc通讯(fins)

c# 教程

相关文章