命名空间: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
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路

















