TcpClient tcpClient;
byte[] byteBuffer= new byte[1024*4];
tcpClient.Client.BeginReceive(byteBuffer, 0, byteBuffer.Length, SocketFlags.None, ReceiveCallBack, null);
// 参数:
// buffer:
// 类型的数组 System.Byte ,它是接收到的数据的存储位置。
如上代码片段所示:当发送端以10ms的间隔频率密集发送数据时,接收方利用Thread.Sleep(10000) 刻意等待10s 后观察测试结果:
发送方发了382次,此时接收方数据先写入socket系统缓冲区累加了,但我们程序读取延时,所以只用了6次就全部读取完了。
如果把上面伪代码的 byteBuffer 设置为发送数据长度(测试发送的数据长度为48:)的一半:即 byte[] byteBuffer=new byte[24];
再次测试发现接收次数为发送次数的两倍,这个好理解:接收容量小了一半,次数就要增加一倍,此时和是否有Sleep无关。Sleep等待只是使得接收数据变慢了。
由上可知:这个buffer参数 太小,则接收太慢,如果参数过大,则可以最大化利用网络I/O性能,但相应速度可能下降,通常要保持一个合理的值,如1024*2 或1024*4 等;
附加一个Socket异步接收模型:参考了
这个Blog
的封装,但实际测试有些bug,做了些改进:
比如连接时,不小心触发了多次连接就可能报异常:
System.InvalidOperationException:“同一个套接字上正在进行另一个异步操作时,不能调用 BeginConnect
另外测试发现一个比较严重的bug,如果客户端Socket异步发送频繁:比如:
for(int i=0;i<(int)this.numericUpDown1.Value;i++)
PipeReader l100 = new PipeReader { PipeCode ="#"+ (i + 1).ToString("0000"), ProductType= ProductType.S45, IsNormalCode=true };
client.SendAsync(l100.ToBytes());
此Socket异步模型会导致数据漏收,比如发了50个,实际只收到了2,3个,问题发生的原因在线程同步锁ManualResetEvent的使用导致,去掉这个锁的逻辑,可以接受完整;或者在客户端发送消息时加上延时,则也可接收完整的回调;
//友情提示:下面的封装异步Tcp客户端,可以拿来做测试用,如果实际项目利用需要谨慎使用
public class AsynSocketClient
#region private
/// <summary>
/// 用于控制异步接收消息
/// </summary>
// private ManualResetEvent doReceive = new ManualResetEvent(false);
private TcpClient tcpClient;
//标识客户端是否接收数据
private bool isStopWork = false;
#endregion
/// <summary>
/// 是否释放对象了
/// </summary>
public bool IsClosed { get => isStopWork; set => isStopWork = value; }
#region 事件
/// <summary>
/// 客户端连接完成、发送完成、连接异常或者服务端关闭触发的事件
/// </summary>
public event Action<TcpClient, SocketAction> Completed;
/// <summary>
/// 客户端接收消息触发的事件
/// </summary>
public event EventHandler<DataEventArgs> Received;
#endregion
public AsynSocketClient()
tcpClient = new TcpClient();
#region 连接
/// <summary>
/// 异步连接
/// </summary>
/// <param name="ip">要连接的服务器的ip地址</param>
/// <param name="port">要连接的服务器的端口</param>
public void ConnectAsync(string ip, int port)
IPAddress ipAddress = null;
ipAddress = IPAddress.Parse(ip);
catch (Exception)
throw new Exception("ip地址格式不正确,请使用正确的ip地址!");
if (!tcpClient.Connected)
tcpClient.BeginConnect(ipAddress, port, ConnectCallBack, tcpClient);
else if (isStopWork)
isStopWork = false;
OnComplete(tcpClient, SocketAction.Connect);
catch
/// <summary>
/// 异步连接的回调函数
/// </summary>
/// <param name="ar"></param>
private void ConnectCallBack(IAsyncResult ar)
TcpClient client = ar.AsyncState as TcpClient;
client.EndConnect(ar);
OnComplete(client, SocketAction.Connect);
catch
#endregion
#region 收发数据
/// <summary>
/// 异步接收消息
/// </summary>
private void ReceiveAsync()
// doReceive.Reset();
StateObject obj = new StateObject();
obj.TcpClient = tcpClient;
tcpClient.Client.BeginReceive(obj.ListData, 0, obj.ListData.Length, SocketFlags.None, ReceiveCallBack, obj);
// doReceive.WaitOne();
/// <summary>
/// 异步发送消息
/// </summary>
/// <param name="msg"></param>
public void SendAsync(string msg)
byte[] listData = Encoding.UTF8.GetBytes(msg);
SendAsync(listData);
public void SendAsync(byte[] bytes)
if (tcpClient.Client == null)
throw new Exception("连接已经断开");
if (isStopWork)
return;
tcpClient.Client.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallBack, tcpClient);
catch (SocketException ex)
if (ex.ErrorCode == (int)SocketError.ConnectionAborted)
throw new Exception("连接已经断开");
private void ReceiveCallBack(IAsyncResult ar)
StateObject state = ar.AsyncState as StateObject;
int count = -1;
if (isStopWork)
return;
count = state.TcpClient.Client.EndReceive(ar);
//doReceive.Set();
catch (Exception ex)
//如果发生异常,说明客户端失去连接,触发关闭事件
Stop();
OnComplete(state.TcpClient, SocketAction.Close);
if (count > 0)
Received?.Invoke(this, new DataEventArgs() { Data = state.ListData.Take<byte>(count).ToArray() });
private void SendCallBack(IAsyncResult ar)
TcpClient client = ar.AsyncState as TcpClient;
client.Client.EndSend(ar);
OnComplete(client, SocketAction.SendMsg);
catch (Exception)
//如果发生异常,说明客户端失去连接,触发关闭事件
Stop();
OnComplete(client, SocketAction.Close);
#endregion
public virtual void OnComplete(TcpClient client, SocketAction action)
if (Completed != null)
Completed(client, action);
if (action == SocketAction.Connect)
// 接收数据
ThreadPool.QueueUserWorkItem(x =>
while (!isStopWork)
ReceiveAsync();
Thread.Sleep(20);
catch (Exception)
Stop();
OnComplete(client, SocketAction.Close);
else if (action == SocketAction.Close)
Thread.Sleep(50);
this.Received = null;
tcpClient.Close();
catch
void Stop()
isStopWork = true;
public void Close()
if (tcpClient != null)
Stop();
IsClosed = true;
Completed = null;
Received = null;
tcpClient.GetStream().Close();
catch(Exception ex)
/// <summary>
/// 接收socket的行为
/// </summary>
public enum SocketAction
/// <summary>
/// socket发生连接
/// </summary>
Connect = 1,
/// <summary>
/// socket发送数据
/// </summary>
SendMsg = 2,
/// <summary>
/// socket关闭
/// </summary>
Close = 4
public class StateObject
public TcpClient TcpClient { get; set; }
private byte[] listData = new byte[1024*4];
/// <summary>
/// 接收的数据
/// </summary>
public byte[] ListData
return listData;
listData = value;
public class DataEventArgs : EventArgs
public byte[] Data
public int Offset
public int Length
TcpClient tcpClient;byte[] byteBuffer= new byte[1024*4];tcpClient.Client.BeginReceive(byteBuffer, 0, byteBuffer.Length, SocketFlags.None, ReceiveCallBack, null); // 参数: // buffer:...
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
新建socket所使用的参数均为系统预定义的量,直接选取使用。
listener.Bind(localEndPoint);
localEndPoint 表示一个
.Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都没有直接为Connect/BeginConnect提供超时控制机制。因此,当服务器未处于监听状态,或者发生网络故障时,客户端连接请求会被迫等待很长一段时间,直到抛出异常。默认的等待时间长达20~30s。.Net Socket库的SocketOptionName.SendTimeout提供了控制发送数据的超时时间,但并非本文讨论的连接请求的超时时间。实现下面是实现的关键代码:
代码如下:class TimeOutSocket{ private static bool I
C#使用OleDB操作ACCESS
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=” + NewFileName + “;User Id=uid;Jet OLEDB:Database Password=pwd;”;
完整错误信息:
{System.InvalidOperationExc...
Socket是什么呢?
参考:https://blog.csdn.net/jia12216/article/details/82702960
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
Socket通信过程介绍:
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(li
Thread th = new Thread(new ThreadStart(SocketInit));
th.IsBackground = true;
th.Start();*/
SocketInit();
Console.ReadKey().
代码下载点击这里
异步开发设计思路和同步开发设计思路一样可以简单看下同步开发
异步开发的区别在于,接收信号的方法和发送信息接收信息的方法还有连接的方式采用了异步模式。
接收信号采用 Socket 的BeginAccept()
发数据采用BeginSend()
接收数据采用的BeginReceive()
连接采用的是BeginConnect()
这些方法的具体用法可以自行百度。
下面来看服务器的核心代码。
监听代码:
<br />当你发现自己最受欢迎的一篇blog其实大错特错时,这绝对不是一件让人愉悦的事。<br />
《 IO - 同步,异步,阻塞,非阻塞
》是我在开始学习epoll和libevent的时候写的,主要的思路来自于文中的那篇link
。写完之后发现很多人都很喜欢,我还是非常开心的,也说明这个问题确实困扰了很多人。随着学习的深入,渐渐的感觉原来的理解有些偏差,但是还是没引起自己的重视,觉着都是一些小错误,无伤大雅。直到有位博友问了一个问题,我重新查阅了一些更权威的资料,才发现原来的文章中有很大的理论错