命名空间:netMarketing.Net.NetSocket.SocketClient
功能:同步读写Tcp客户端
功能详细说明:
这个类名字中有一个socket,指的是它功能的实现是采用Socket套接字方式实现的。这个套接字运行于客户端,所以这个类叫SocketClient。
那么Socket连接跟Tcp连接有什么不同呢?
创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
因此,本类实际上是利用Socket套接字,并且传输层采用Tcp协议实现的一个Tcp客户端功能类。
它的功能就是下面这个调试工具的TCP Client功能。
常用函数列表:
成员方法: //连接到服务端,输入服务端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; } }
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不同来区别。
如果点“点击计算厚度”按钮,则程序会同时读取上下两个激光头的数据并做出厚度计算。
在这个例程中,要特别注意下面几点:
注意方法SendAndGetData(),它用lock把tcp读写功能锁起来,是为了避免多线程同时执行这个方法。这个非常重要。
上下激头同时读取数据,采用了asynOperation类,这是一个异常线程类,可以比较方便用来执行类似于同步执行XYZ轴回原点的任务。这个类请参阅:“asynOperation(异步线程类)”
函数outmsg(),是在C#中安全访问控件的标准做法之一,它的作用是防止跨线程调用UI控件。有关这个话题,可以参考贴子
“C#中Invoke的用法”
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

