|
|
@@ -1,89 +1,49 @@
|
|
|
using System;
|
|
|
using System.Net;
|
|
|
using System.Net.Sockets;
|
|
|
+using System.Threading.Tasks;
|
|
|
|
|
|
namespace TNet
|
|
|
{
|
|
|
- public class TSocket: IDisposable
|
|
|
+ public class TSocket
|
|
|
{
|
|
|
- private Socket socket;
|
|
|
- private readonly TPoller poller;
|
|
|
- private readonly SocketAsyncEventArgs innSocketAsyncEventArgs = new SocketAsyncEventArgs();
|
|
|
- private readonly SocketAsyncEventArgs outSocketAsyncEventArgs = new SocketAsyncEventArgs();
|
|
|
- private readonly TBuffer recvBuffer = new TBuffer();
|
|
|
- private readonly TBuffer sendBuffer = new TBuffer();
|
|
|
- public Action RecvAction { get; set; }
|
|
|
- public Action<TSocket> AcceptAction { get; set; }
|
|
|
+ private IPoller poller;
|
|
|
+ private readonly Socket socket;
|
|
|
+ private readonly SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();
|
|
|
|
|
|
- public TSocket(TPoller poller)
|
|
|
+ public TSocket(IPoller poller)
|
|
|
{
|
|
|
this.poller = poller;
|
|
|
this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
|
- this.outSocketAsyncEventArgs.Completed += this.OnComplete;
|
|
|
- this.innSocketAsyncEventArgs.Completed += this.OnComplete;
|
|
|
+ this.socketAsyncEventArgs.Completed += this.OnComplete;
|
|
|
}
|
|
|
|
|
|
- public TSocket(TPoller poller, Socket socket)
|
|
|
+ public Socket Socket
|
|
|
{
|
|
|
- this.poller = poller;
|
|
|
- this.socket = socket;
|
|
|
- this.outSocketAsyncEventArgs.Completed += this.OnComplete;
|
|
|
- this.innSocketAsyncEventArgs.Completed += this.OnComplete;
|
|
|
- }
|
|
|
-
|
|
|
- public void Dispose()
|
|
|
- {
|
|
|
- if (this.socket == null)
|
|
|
+ get
|
|
|
{
|
|
|
- return;
|
|
|
+ return this.socket;
|
|
|
}
|
|
|
- socket.Dispose();
|
|
|
- this.socket = null;
|
|
|
}
|
|
|
|
|
|
- public void Connect(string host, int port)
|
|
|
+ public void Dispose()
|
|
|
{
|
|
|
- if (socket.ConnectAsync(this.innSocketAsyncEventArgs))
|
|
|
+ if (this.poller == null)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- this.poller.Add(this.OnConnComplete);
|
|
|
- }
|
|
|
-
|
|
|
- public void Accept(int port)
|
|
|
- {
|
|
|
- this.socket.Bind(new IPEndPoint(IPAddress.Any, port));
|
|
|
- this.socket.Listen(100);
|
|
|
- this.BeginAccept();
|
|
|
+ this.socket.Dispose();
|
|
|
+ this.poller = null;
|
|
|
}
|
|
|
|
|
|
- public bool Recv(byte[] buffer)
|
|
|
+ public void Bind(string host, int port)
|
|
|
{
|
|
|
- if (buffer.Length > this.RecvSize)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- this.recvBuffer.RecvFrom(buffer);
|
|
|
- return true;
|
|
|
+ this.socket.Bind(new IPEndPoint(IPAddress.Parse(host), port));
|
|
|
}
|
|
|
|
|
|
- public void Send(byte[] buffer)
|
|
|
+ public void Listen(int backlog)
|
|
|
{
|
|
|
- bool needBeginSend = this.sendBuffer.Count == 0;
|
|
|
- this.sendBuffer.SendTo(buffer);
|
|
|
- if (needBeginSend)
|
|
|
- {
|
|
|
- this.BeginSend();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public int RecvSize
|
|
|
- {
|
|
|
- get
|
|
|
- {
|
|
|
- return this.recvBuffer.Count;
|
|
|
- }
|
|
|
+ this.socket.Listen(backlog);
|
|
|
}
|
|
|
|
|
|
private void OnComplete(object sender, SocketAsyncEventArgs e)
|
|
|
@@ -92,157 +52,119 @@ namespace TNet
|
|
|
switch (e.LastOperation)
|
|
|
{
|
|
|
case SocketAsyncOperation.Accept:
|
|
|
- action = () => this.OnAcceptComplete(e.AcceptSocket);
|
|
|
+ action = () => OnAcceptComplete(e);
|
|
|
e.AcceptSocket = null;
|
|
|
break;
|
|
|
case SocketAsyncOperation.Connect:
|
|
|
- action = this.OnConnComplete;
|
|
|
+ action = () => OnConnectComplete(e);
|
|
|
break;
|
|
|
case SocketAsyncOperation.Disconnect:
|
|
|
- action = this.OnDisconnect;
|
|
|
+ action = () => OnDisconnectComplete(e);
|
|
|
break;
|
|
|
case SocketAsyncOperation.Receive:
|
|
|
- action = () => this.OnRecvComplete(e.BytesTransferred);
|
|
|
+ action = () => OnRecvComplete(e);
|
|
|
break;
|
|
|
case SocketAsyncOperation.Send:
|
|
|
- action = () => this.OnSendComplete(e.BytesTransferred);
|
|
|
+ action = () => OnSendComplete(e);
|
|
|
break;
|
|
|
default:
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
}
|
|
|
-
|
|
|
- this.poller.Add(action);
|
|
|
- }
|
|
|
|
|
|
- private void OnDisconnect()
|
|
|
- {
|
|
|
- this.Dispose();
|
|
|
+ this.poller.Add(action);
|
|
|
}
|
|
|
|
|
|
- private void OnAcceptComplete(Socket sock)
|
|
|
+ public Task<bool> ConnectAsync(string host, int port)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- TSocket newSocket = new TSocket(poller, sock);
|
|
|
- if (this.AcceptAction != null)
|
|
|
+ var tcs = new TaskCompletionSource<bool>();
|
|
|
+ this.socketAsyncEventArgs.UserToken = tcs;
|
|
|
+ this.socketAsyncEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
|
|
|
+ if (!this.socket.ConnectAsync(this.socketAsyncEventArgs))
|
|
|
{
|
|
|
- this.AcceptAction(newSocket);
|
|
|
+ this.poller.Add(() => { OnConnectComplete(this.socketAsyncEventArgs); });
|
|
|
}
|
|
|
- this.BeginAccept();
|
|
|
+ return tcs.Task;
|
|
|
}
|
|
|
|
|
|
- private void OnConnComplete()
|
|
|
+ private static void OnConnectComplete(SocketAsyncEventArgs e)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.BeginRecv();
|
|
|
+ var tcs = (TaskCompletionSource<bool>)e.UserToken;
|
|
|
+ tcs.SetResult(true);
|
|
|
}
|
|
|
|
|
|
- private void OnRecvComplete(int bytesTransferred)
|
|
|
+ public Task<bool> AcceptAsync(TSocket accpetSocket)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
+ var tcs = new TaskCompletionSource<bool>();
|
|
|
+ this.socketAsyncEventArgs.UserToken = tcs;
|
|
|
+ this.socketAsyncEventArgs.AcceptSocket = accpetSocket.socket;
|
|
|
+ if (!this.socket.AcceptAsync(this.socketAsyncEventArgs))
|
|
|
{
|
|
|
- return;
|
|
|
- }
|
|
|
- this.recvBuffer.LastIndex += bytesTransferred;
|
|
|
- if (this.recvBuffer.LastIndex == TBuffer.ChunkSize)
|
|
|
- {
|
|
|
- this.recvBuffer.LastIndex = 0;
|
|
|
- this.recvBuffer.AddLast();
|
|
|
- }
|
|
|
-
|
|
|
- this.BeginRecv();
|
|
|
-
|
|
|
- if (this.RecvAction != null)
|
|
|
- {
|
|
|
- this.RecvAction();
|
|
|
+ Action action = () => OnAcceptComplete(this.socketAsyncEventArgs);
|
|
|
+ this.poller.Add(action);
|
|
|
}
|
|
|
+ return tcs.Task;
|
|
|
}
|
|
|
|
|
|
- private void OnSendComplete(int bytesTransferred)
|
|
|
+ private static void OnAcceptComplete(SocketAsyncEventArgs e)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this.sendBuffer.FirstIndex += bytesTransferred;
|
|
|
- if (this.sendBuffer.FirstIndex == TBuffer.ChunkSize)
|
|
|
- {
|
|
|
- this.sendBuffer.FirstIndex = 0;
|
|
|
- this.sendBuffer.RemoveFirst();
|
|
|
- }
|
|
|
-
|
|
|
- // 如果没有数据可以发送,则返回
|
|
|
- if (this.sendBuffer.Count == 0)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 继续发送数据
|
|
|
- this.BeginSend();
|
|
|
+ var tcs = (TaskCompletionSource<bool>)e.UserToken;
|
|
|
+ tcs.SetResult(true);
|
|
|
}
|
|
|
|
|
|
- private void BeginAccept()
|
|
|
+ public Task<int> RecvAsync(byte[] buffer, int offset, int count)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
+ var tcs = new TaskCompletionSource<int>();
|
|
|
+ this.socketAsyncEventArgs.UserToken = tcs;
|
|
|
+ this.socketAsyncEventArgs.SetBuffer(buffer, offset, count);
|
|
|
+ if (!this.socket.ReceiveAsync(this.socketAsyncEventArgs))
|
|
|
{
|
|
|
- return;
|
|
|
+ Action action = () => OnRecvComplete(this.socketAsyncEventArgs);
|
|
|
+ this.poller.Add(action);
|
|
|
}
|
|
|
-
|
|
|
- if (this.socket.AcceptAsync(this.innSocketAsyncEventArgs))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- Action action = () => this.OnAcceptComplete(this.innSocketAsyncEventArgs.AcceptSocket);
|
|
|
- this.poller.Add(action);
|
|
|
+ return tcs.Task;
|
|
|
}
|
|
|
|
|
|
- private void BeginRecv()
|
|
|
+ private static void OnRecvComplete(SocketAsyncEventArgs e)
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ var tcs = (TaskCompletionSource<int>)e.UserToken;
|
|
|
+ tcs.SetResult(e.BytesTransferred);
|
|
|
+ }
|
|
|
|
|
|
- this.innSocketAsyncEventArgs.SetBuffer(this.recvBuffer.Last, this.recvBuffer.LastIndex, TBuffer.ChunkSize - this.recvBuffer.LastIndex);
|
|
|
- if (this.socket.ReceiveAsync(this.innSocketAsyncEventArgs))
|
|
|
+ public Task<int> SendAsync(byte[] buffer, int offset, int count)
|
|
|
+ {
|
|
|
+ var tcs = new TaskCompletionSource<int>();
|
|
|
+ this.socketAsyncEventArgs.UserToken = tcs;
|
|
|
+ this.socketAsyncEventArgs.SetBuffer(buffer, offset, count);
|
|
|
+ if (!this.socket.SendAsync(this.socketAsyncEventArgs))
|
|
|
{
|
|
|
- return;
|
|
|
+ Action action = () => OnSendComplete(this.socketAsyncEventArgs);
|
|
|
+ this.poller.Add(action);
|
|
|
}
|
|
|
+ return tcs.Task;
|
|
|
+ }
|
|
|
|
|
|
- Action action = () => this.OnRecvComplete(this.innSocketAsyncEventArgs.BytesTransferred);
|
|
|
- this.poller.Add(action);
|
|
|
+ private static void OnSendComplete(SocketAsyncEventArgs e)
|
|
|
+ {
|
|
|
+ var tcs = (TaskCompletionSource<int>)e.UserToken;
|
|
|
+ tcs.SetResult(e.BytesTransferred);
|
|
|
}
|
|
|
|
|
|
- private void BeginSend()
|
|
|
+ public Task<bool> DisconnectAsync()
|
|
|
{
|
|
|
- if (this.socket == null)
|
|
|
+ var tcs = new TaskCompletionSource<bool>();
|
|
|
+ this.socketAsyncEventArgs.UserToken = tcs;
|
|
|
+ if (!this.socket.DisconnectAsync(this.socketAsyncEventArgs))
|
|
|
{
|
|
|
- return;
|
|
|
+ Action action = () => OnDisconnectComplete(this.socketAsyncEventArgs);
|
|
|
+ this.poller.Add(action);
|
|
|
}
|
|
|
+ return tcs.Task;
|
|
|
+ }
|
|
|
|
|
|
- int count = 0;
|
|
|
- if (TBuffer.ChunkSize - this.sendBuffer.FirstIndex < this.sendBuffer.Count)
|
|
|
- {
|
|
|
- count = TBuffer.ChunkSize - this.sendBuffer.FirstIndex;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- count = this.sendBuffer.Count;
|
|
|
- }
|
|
|
- this.outSocketAsyncEventArgs.SetBuffer(this.sendBuffer.First, this.sendBuffer.FirstIndex, count);
|
|
|
- if (this.socket.SendAsync(outSocketAsyncEventArgs))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- Action action = () => this.OnSendComplete(this.outSocketAsyncEventArgs.BytesTransferred);
|
|
|
- this.poller.Add(action);
|
|
|
+ private static void OnDisconnectComplete(SocketAsyncEventArgs e)
|
|
|
+ {
|
|
|
+ var tcs = (TaskCompletionSource<bool>)e.UserToken;
|
|
|
+ tcs.SetResult(true);
|
|
|
}
|
|
|
}
|
|
|
}
|