C#实现异步阻塞TCP(Send,Receive,Accept,Connect)
1.类
(1)服务器端操作类
public class TcpServiceSocket
{
//接收数据事件
public Action<Socket, string> recvMessageEvent = null;
//发送结果事件
public Action<int> sendResultEvent = null;
//允许连接到tcp服务器的tcp客户端数量
private int numConnections = 0;
//连接socket
private Socket listenSocket = null;
//tcp服务器ip
private string host = "";
//tcp服务器端口
private int port = 0;
//控制tcp客户端连接数量的信号量
private Semaphore maxNumberAcceptedClients = null;
private int bufferSize = 1024;
private List<Socket> clientSockets = null; public TcpServiceSocket(string host, int port, int numConnections)
{
if (string.IsNullOrEmpty(host))
throw new ArgumentNullException("host cannot be null");
if (port < 1 || port > 65535)
throw new ArgumentOutOfRangeException("port is out of range");
if (numConnections <= 0 || numConnections > int.MaxValue)
throw new ArgumentOutOfRangeException("_numConnections is out of range"); this.host = host;
this.port = port;
this.numConnections = numConnections;
clientSockets = new List<Socket>();
maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
} public void Start()
{
try
{
listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Parse(host), port));
listenSocket.Listen(numConnections);
AcceptAsync();
}
catch (Exception)
{
}
} private async void AcceptAsync()
{
await Task.Run(new Action(() =>
{
while (true)
{
maxNumberAcceptedClients.WaitOne(); try
{
Socket acceptSocket = listenSocket.Accept();
if (acceptSocket == null)
continue; clientSockets.Add(acceptSocket);
RecvAsync(acceptSocket);
}
catch (Exception)
{
maxNumberAcceptedClients.Release();
}
}
}));
} private async void RecvAsync(Socket acceptSocket)
{
await Task.Run(new Action(() =>
{
int len = 0;
byte[] buffer = new byte[bufferSize]; try
{
while ((len = acceptSocket.Receive(buffer, bufferSize, SocketFlags.None)) > 0)
{
if (recvMessageEvent != null)
recvMessageEvent(acceptSocket, Encoding.UTF8.GetString(buffer, 0, len));
}
}
catch (Exception)
{
CloseClientSocket(acceptSocket);
}
}));
} public async void SendAsync(Socket acceptSocket, string message)
{
await Task.Run(new Action(() =>
{
int len = 0;
byte[] buffer = Encoding.UTF8.GetBytes(message);
try
{
if ((len = acceptSocket.Send(buffer, buffer.Length, SocketFlags.None)) > 0)
{
if (sendResultEvent != null)
sendResultEvent(len);
}
}
catch (Exception)
{
CloseClientSocket(acceptSocket);
}
}));
} public async void SendMessageToAllClientsAsync(string message)
{
await Task.Run(new Action(() =>
{
foreach (var socket in clientSockets)
{
SendAsync(socket, message);
}
}));
} private void CloseClientSocket(Socket acceptSocket)
{
try
{
acceptSocket.Shutdown(SocketShutdown.Both);
}
catch { }
try
{
acceptSocket.Close();
}
catch { } maxNumberAcceptedClients.Release();
} public void CloseAllClientSocket(Socket acceptSocket)
{
try
{
foreach (var socket in clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
}
}
catch { }
try
{
foreach (var socket in clientSockets)
{
socket.Close();
}
}
catch { } try
{
listenSocket.Shutdown(SocketShutdown.Both);
}
catch { }
try
{
listenSocket.Close();
}
catch { } try
{
maxNumberAcceptedClients.Release(clientSockets.Count);
clientSockets.Clear();
}
catch { }
}
}
(2)客户端操作类
public class TcpClientSocket
{
//接收数据事件
public Action<string> recvMessageEvent = null;
//发送结果事件
public Action<int> sendResultEvent = null;
//连接socket
private Socket connectSocket = null;
//tcp服务器ip
private string host = "";
//tcp服务器端口
private int port = 0;
private int bufferSize = 1024; public TcpClientSocket(string host, int port)
{
if (string.IsNullOrEmpty(host))
throw new ArgumentNullException("host cannot be null");
if (port < 1 || port > 65535)
throw new ArgumentOutOfRangeException("port is out of range"); this.host = host;
this.port = port;
} public void Start()
{
try
{
connectSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connectSocket.Connect(host, port);
RecvAsync();
}
catch (Exception)
{
}
} private async void RecvAsync()
{
await Task.Run(new Action(() =>
{
int len = 0;
byte[] buffer = new byte[bufferSize];
try
{
while ((len = connectSocket.Receive(buffer, bufferSize, SocketFlags.None)) > 0)
{
if (recvMessageEvent != null)
recvMessageEvent(Encoding.UTF8.GetString(buffer, 0, len));
}
}
catch (Exception)
{
Restart();
}
}));
} public async void SendAsync(string message)
{
await Task.Run(new Action(() =>
{
int len = 0;
byte[] buffer = Encoding.UTF8.GetBytes(message);
try
{
if ((len = connectSocket.Send(buffer, buffer.Length, SocketFlags.None)) > 0)
{
if (sendResultEvent != null)
sendResultEvent(len);
}
}
catch (Exception)
{
Restart();
}
}));
} public void CloseClientSocket()
{
try
{
connectSocket.Shutdown(SocketShutdown.Both);
}
catch { }
try
{
connectSocket.Close();
}
catch { }
} public void Restart()
{
CloseClientSocket();
Start();
} }
2.使用
(1)服务器:
public partial class Form1 : Form
{
TcpServiceSocket tcpServiceSocket = null;
private readonly string ip = "192.168.172.142";
private readonly int port = 8090; public Form1()
{
InitializeComponent();
tcpServiceSocket = new TcpServiceSocket(ip, port, 10);
tcpServiceSocket.recvMessageEvent += new Action<Socket, string>(Recv);
} private void Recv(Socket socket, string message)
{
this.BeginInvoke(new Action(() =>
{
tbRecv.Text += message + "\r\n";
}));
} private void btnStart_Click(object sender, EventArgs e)
{
tcpServiceSocket.Start();
} private void btnSend_Click(object sender, EventArgs e)
{
string message = tbSend.Text.Trim();
if (string.IsNullOrEmpty(message))
return; tcpServiceSocket.SendMessageToAllClientsAsync(message);
tbSend.Text = "";
}
}
(2)客户端
public partial class Form1 : Form
{
private TcpClientSocket tcpClientSocket = null;
private readonly string ip = "192.168.172.142";
private readonly int port = 8090; public Form1()
{
InitializeComponent();
tcpClientSocket = new TcpClientSocket(ip, port);
tcpClientSocket.recvMessageEvent += new Action<string>(Recv);
} private void Recv(string message)
{
this.BeginInvoke(new Action(() =>
{
tbRecv.Text += message + "\r\n";
}));
} private void btnStart_Click(object sender, EventArgs e)
{
tcpClientSocket.Start();
} private void btnSend_Click(object sender, EventArgs e)
{
string message = tbSend.Text.Trim();
if (string.IsNullOrEmpty(message))
return; tcpClientSocket.SendAsync(message);
tbSend.Text = "";
}
}
C#实现异步阻塞TCP(Send,Receive,Accept,Connect)的更多相关文章
- C#实现异步阻塞TCP(SocketAsyncEventArgs,SendAsync,ReceiveAsync,AcceptAsync,ConnectAsync)
1.类 (1)socket IO操作内存管理类 BufferManager // This class creates a single large buffer which can be divid ...
- {Python之进程} 背景知识 什么是进程 进程调度 并发与并行 同步\异步\阻塞\非阻塞 进程的创建与结束 multiprocess模块 进程池和mutiprocess.Poll
Python之进程 进程 本节目录 一 背景知识 二 什么是进程 三 进程调度 四 并发与并行 五 同步\异步\阻塞\非阻塞 六 进程的创建与结束 七 multiprocess模块 八 进程池和mut ...
- GIL 线程池 进程池 同步 异步 阻塞 非阻塞
1.GIL 是一个全局解释器锁,是一种互斥锁 为什么需要GIL锁:因为一个python.exe进程中只有一份解释器,如果这个进程开启了多个线程都要执行代码 多线程之间要竞争解释器,一旦竞争就有可能出现 ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)
9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...
- 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor
开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...
- 操作系统介绍-操作系统历史,IO,进程的三态,同步异步阻塞非阻塞
1.操作系统历史 2.进程,IO,同步异步阻塞非阻塞 操作系统历史: 手工操作: 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念. 手工操 ...
- 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...
- [TCP/IP]TCP服务端accept发生在三次握手的哪一个阶段
TCP服务端accept发生在三次握手之后 客户端socket()==>connect()==>write()==>read()服务端socket()==>bind()==&g ...
随机推荐
- HADR和TSA需要注意的问题
1.必须将主备数据库都执行一次完全备份,然后使用主库执行online备份后同步至备库: 2.同一台服务器只能添加一个TSA集群管理器,此服务器中无论有几个实例和几个数据库,都会被添加至首次创建的集群中 ...
- 【LOJ】#3103. 「JSOI2019」节日庆典
LOJ#3103. 「JSOI2019」节日庆典 能当最小位置的值一定是一个最小后缀,而有用的最小后缀不超过\(\log n\)个 为什么不超过\(\log n\)个,看了一下zsy的博客.. 假如\ ...
- Kubernetes---容器探针
⒈含义 探针是由各个节点的kubelet对容器执行的定期诊断.要执行诊断,kubelet 调用由容器实现的Handler[处理程序].有三种类型的处理程序: >ExecAction:在容器内执行 ...
- (六)mybatis 全局配置文件讲解
目录 properties (属性) settings 全局参数配置 typeAliases 别名设置 typeHandlers 类型处理器 mapper (映射器) 细节 properties (属 ...
- 前端vue组件传参
## 路由传参 """ 转跳: <router-link :to="'/course/'+course.id">{{course.name ...
- getContextPath、getServletPath、getRequestURI、getRealPath、getRequestURL、getPathInfo();的区别
<% out.println("getContextPath: "+request.getContextPath()+"<br/>"); ou ...
- visual studio 用 vs code 的 hot key
记得 2 年多前开始用 vs code, 一开始非常不适应它的 hot key 一心想把 vs code 的 hot key 全改成 visual studio 的,但一直没有找到比较方便的办法 (总 ...
- java都13了, 8的新特性你还没不会用吗
前言 java13都已经来了,很多同学还停留在使用java5的东西.如果在日常开发中没有使用上java8的一些新特性或者不会用.这篇文章对你可能有帮助. lambda表达式 介绍 lambda表达式是 ...
- hdu 6053 trick gcd 容斥
http://acm.hdu.edu.cn/showproblem.php?pid=6053 题意:给定一个数组,我们定义一个新的数组b满足bi<ai 求满足gcd(b1,b2....bn)&g ...
- Linux上定时shell脚本
原文链接:http://www.92coder.com/9-Linux%E5%AE%9A%E6%97%B6shell%E8%84%9A%E6%9C%AC/#more 本文主要介绍在Linux系统上部署 ...