[netMarketing类库] SocketClient类:同步读写的Tcp客户端

命名空间:netMarketing.Net.NetSocket.SocketClient

功能:同步读写Tcp客户端


功能详细说明:
这个类名字中有一个socket,指的是它功能的实现是采用Socket套接字方式实现的。这个套接字运行于客户端,所以这个类叫SocketClient。

那么Socket连接跟Tcp连接有什么不同呢?

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。 
因此,本类实际上是利用Socket套接字,并且传输层采用Tcp协议实现的一个Tcp客户端功能类。

它的功能就是下面这个调试工具的TCP Client功能。

image.png

常用函数列表:

成员方法:
//连接到服务端,输入服务端ip和端口号
public bool Connecting(string address, int port)
//中断连接后重新连接	
public bool ReuseSocket()	
//中断连接			
public void Disconnect(bool reuseSocket = true)	

//下面两个是发送数据到服务器	
public bool SendMsg(string Msg)				
public bool SendMsg(byte[] Msg)


//下面三个重载函数是接收服务器返回的数据
//这个函数缓冲区默认大小为4194304字节
public bool ReceiveMsg(out string Msg)
//这个函数缓冲区默认大小1024字节
public bool ReceiveMsg(out byte[] byteMsg)
//这个函数缓冲区为用户自定义大小dataLength
public bool ReceiveMsg(out byte[] byteMsg, uint dataLength)

//设置接收缓冲区数据时的超时大小,毫秒
public bool SetReceiveTimeOut(int millisecond)

属性:
public bool Available		//sockClient客户端是否有效
public bool IsConnected		//当前sockClient客户端是否连接上
public int ReceiveBufferSize	//当前客户端连接的缓冲区有多大	


参考例子:

首先你要用socket调试工具,创建一个TCP Server,端口号9600.
我们程序这边ip填写本地IP 127.0.01, 端口号9600,点击“连接”
然后点击发送,字符串发送到服务器端。
这个时候你会发现我们的程序会卡死,因为它在下面的函数中,我们程序发送字符串后,马上函数ReceiveMsg进行超时等待。
这个时候你应该在4秒钟内去Socket调试工具发送一条字符串过来。这时候我们的程序才可以继续。
因此,这就是为什么本文标题上称这个类为同步读写的TCP客户端

 private bool SendAndGetData(Byte[] readCmd, out Byte[] rcvByte, uint byteLength)
        {
            //注意,tcp发送数据与接收数据的功能要用lock锁起来,防止多线程同时执行本函数。
            lock (obj)
            {
                rcvByte = new byte[byteLength];
                if (!SktClient.SendMsg(readCmd)) return false;
                if (!SktClient.ReceiveMsg(out rcvByte, byteLength)) return false;

                return true;
            }
        }

image.png

using netMarketing.http;
using netMarketing.Net.NetSocket;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace socketclientTest
{
    public partial class Form1 : Form
    {
        private SocketClient SktClient = new SocketClient();
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private bool initNet(string IpAdrr, int Port)
        {
            var f1 = true;
            do
            {
                SktClient = new SocketClient();
                if (!SktClient.Connecting(IpAdrr, Port))
                {
                    outmsg(string.Format("连接 IP {0}, 端口 {1} 时失败!", IpAdrr, Port));
                    f1 = false; break;
                }
                if (!SktClient.SetReceiveTimeOut(4000))
                { f1 = false; break; }

            } while (false);
            return f1;
        }

        private void outmsg(string msg)
        {
            if (rtbRecvMsg.InvokeRequired)
            {
                rtbRecvMsg.Invoke(new Action(() =>
                {
                    rtbRecvMsg.AppendText(msg);
                }));
            }
            else
            {
                rtbRecvMsg.AppendText(msg);
            }
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                if (initNet(tbIP.Text, int.Parse(tbPort.Text)))
                    outmsg("连接成功!");
                else
                    outmsg("连接失败!");
            }
            catch(Exception ex)
            {
                outmsg(ex.Message);
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if(null!=SktClient && tbSendMsg.Text.Length>2  && SktClient.IsConnected)
            {
                sendMsg(tbSendMsg.Text);
            }
        }

        private void sendMsg(string msg)
        {
            var bary = binHelper.toBin(msg);
            byte[] buff=new byte[]{};
            SendAndGetData(bary, out buff, 50);
            if(buff.Length>1)
            {
                rtbRecvMsg.AppendText(new string(Encoding.Default.GetChars(buff)));
            }
        }

        Object obj = new Object();
        private bool SendAndGetData(Byte[] readCmd, out Byte[] rcvByte, uint byteLength)
        {
            //注意,tcp发送数据与接收数据的功能要用lock锁起来,防止多线程同时执行本函数。
            lock (obj)
            {
                rcvByte = new byte[byteLength];
                if (!SktClient.SendMsg(readCmd)) return false;
                if (!SktClient.ReceiveMsg(out rcvByte, byteLength)) return false;

                return true;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (null != SktClient && SktClient.Available)
                SktClient.Disconnect();
        }


    }
}


另一个实例

using netMarketing.http;
using netMarketing.Net.NetSocket;
using netMarketing.thread;
using sharClass;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace zw7000test
{
    public partial class Form1 : Form
    {
        private SocketClient SktClient = new SocketClient();
        private winData configdata = new winData();
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (workInfoFromDisk())
            {
                tbLaserChannel.Text = configdata.laserChannel.ToString();
                tbSum.Text = configdata.dataSum.ToString();
                tbLaserIP.Text = configdata.laserIP;
                tbLaserPort.Text = configdata.laserPort.ToString();
            }
        }


        public bool workInfoFromDisk()
        {
            try
            {
                var res = Serialize.FileDeSerialize(AppDomain.CurrentDomain.BaseDirectory + "autoCaliSetting");
                if (null != res)
                {
                    configdata = res as winData;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool workInfoToDisk()
        {
            try
            {
                Serialize.FileSerialize(AppDomain.CurrentDomain.BaseDirectory + "autoCaliSetting", configdata);
                return true;
            }
            catch (Exception ex)
            {
                throw new ArgumentException(ex.Message);
            }
        }

        private void btnRead_Click(object sender, EventArgs e)
        {
            try
            {
                configdata.laserChannel = int.Parse(tbLaserChannel.Text);
                configdata.dataSum = int.Parse(tbSum.Text);
                configdata.laserIP = tbLaserIP.Text;
                configdata.laserPort = int.Parse(tbLaserPort.Text);
                workInfoToDisk();
                readLaserData(configdata.laserChannel,configdata.dataSum);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        List<double> laserBufferUp = new List<double>();
        List<double> laserBufferDown = new List<double>();
        private void readLaserData(int channelNo,int readSum)
        {
            bool isConnect = false; string lasername = "";
            if (channelNo == 0)
            {
                isConnect = isConnectUp; lasername = "上激光";
                laserBufferUp.Clear();
            }
            else
            {
                isConnect = isConnectDown; lasername = "下激光";
                laserBufferDown.Clear();
            }
            if(!isConnect)
            {
                try
                {
                    InitPort(configdata.laserIP, configdata.laserPort);
                    outmsg(lasername+ "初始化成功!\r\n");
                }
                catch(Exception ex)
                {
                    outmsg(ex.Message + Environment.NewLine); return;
                }
            }
            
            var bary = binHelper.toBin(string.Format("LS 1 {0}\r",readSum));
            var buffer = new byte[] { };
            SendAndGetData(bary, out buffer, (uint)bary.Length);
            outmsg("读取数据 "+new string( Encoding.Default.GetChars(buffer)));

            ShowAlarm.Delay(100);   //等待激光读取完成
            bary = binHelper.toBin(string.Format("LO {0} 0\r", channelNo));
            SendAndGetData(bary, out buffer, (uint)readSum*12);
            var str1 = new string(Encoding.Default.GetChars(buffer));

            var listtmp=str1.Split(new string[] { "," },StringSplitOptions.RemoveEmptyEntries).ToList().ConvertAll((s) => double.Parse(s));
            if (channelNo == 0)
            {
                laserBufferUp = listtmp;
            }
            else
            {
                laserBufferDown = listtmp;
            }
             
            outmsg(str1);
        }

        private void btnCalThickness_Click(object sender, EventArgs e)
        {
            //异步方式同时执行读取激光上头,与激光下头的数据
            var ao = new asynOperation();
            ao.FuncListAdd(readLaserUpData);
            ao.FuncListAdd(readLaserDownData);
            var f1 = ao.AsynFunList();
            outmsg(string.Format("厚度:{0}\r\n", calThickness()));
        }

        private double calThickness()
        {
            if(laserBufferUp.Count==laserBufferDown.Count)
            {
                var list1 = new List<double>();
                for(int i=0;i<laserBufferUp.Count;i++)
                {
                    list1.Add(laserBufferUp[i] + laserBufferDown[i]);
                }
                return list1.Average();
            }
            else
            {
                outmsg("激光上下头采集数据数量不相等!\r\n");
                return 0;
            }
        }

        private bool readLaserUpData()
        {
            readLaserData(0, 10);
            return true;
        }

        private bool readLaserDownData()
        {
            readLaserData(1, 10);
            return true;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                configdata.laserChannel =int.Parse( tbLaserChannel.Text);
                configdata.dataSum = int.Parse(tbSum.Text);
                configdata.laserIP = tbLaserIP.Text;
                configdata.laserPort = int.Parse(tbLaserPort.Text);
                workInfoToDisk();
                Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        
        Object obj = new Object();
        bool SendAndGetData(Byte[] readCmd, out Byte[] rcvByte, uint byteLength)
        {
	    //注意,tcp发送数据与接收数据的功能要用lock锁起来,防止多线程同时执行本函数。
            lock (obj)
            {
                rcvByte = new byte[byteLength];
                if (!SktClient.SendMsg(readCmd)) return false;
                if (!SktClient.ReceiveMsg(out rcvByte, byteLength)) return false;

                return true;
            }
        }

        private void outmsg(string msg)
        {
            if (richTextBox1.InvokeRequired)
            {
                richTextBox1.Invoke(new Action(() =>
                {
                    richTextBox1.AppendText(msg);
                }));
            }
            else
            {
                richTextBox1.AppendText(msg);
            }
        }

        bool isConnectUp = false;
        bool isConnectDown = false;
        public void InitPort(string IpAdrr, int Port)
        {
            bool f1 = true;
            try
            {
                do
                {
                    SktClient = new SocketClient();
                    if (!SktClient.Connecting(IpAdrr, Port))
                    {
                        outmsg(string.Format("连接激光 IP {0}, 端口 {1} 时失败!", IpAdrr, Port));
                        f1 = false; break;
                    }
                    if (!SktClient.SetReceiveTimeOut(4000))
                    { f1 = false; break; }
                    
                } while (false);
                if (IpAdrr.Equals("192.168.250.50"))
                    isConnectUp = f1;
                else
                    isConnectDown = f1;
            }
            catch (Exception ex)
            {
                outmsg(ex.Message);
                if (IpAdrr.Equals("192.168.250.50"))
                    isConnectUp = false;
                else
                    isConnectDown = false;
            }

        }

        public void Close()
        {
            try
            {
                if (SktClient != null)
                {
                    if (SktClient.SockClient != null && SktClient.SockClient.Connected)
                        SktClient.SockClient.Close();
                    SktClient.Dispose();
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


    }

     [Serializable]
    public class winData
    {
        public int laserChannel { get; set; }
        public int dataSum { get; set; }
        public string laserIP { get; set; }
        public int laserPort { get; set; }
    }

}

上面的代码的功能是读取两个激光头的数据。
激光头分为上头与下头,如果点“读取”按钮,则可以读取指定IP的一个头的数据,它们以IP不同来区别。
如果点“点击计算厚度”按钮,则程序会同时读取上下两个激光头的数据并做出厚度计算。

image.png

在这个例程中,要特别注意下面几点:

  • 注意方法SendAndGetData(),它用lock把tcp读写功能锁起来,是为了避免多线程同时执行这个方法。这个非常重要。

  • 上下激头同时读取数据,采用了asynOperation类,这是一个异常线程类,可以比较方便用来执行类似于同步执行XYZ轴回原点的任务。这个类请参阅:“asynOperation(异步线程类)

  • 函数outmsg(),是在C#中安全访问控件的标准做法之一,它的作用是防止跨线程调用UI控件。有关这个话题,可以参考贴子
    C#中Invoke的用法


--------------------- 

作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

返回类库功能说明目录


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864