서버는 블럭없이 대기하는 부분,블럭없이 자료수신하는 부분으로 구성하고 있습니다.
제 구상.
1. loopAccept메서드가 i/o 블럭없이 처리됨.
2. client 접속이 들어오면 TaskCompletionSource의 onComplete 메서드가 동작됩니다.
여기서 접속된 클라이언트를 저장하고, 메시지를 받는 LoopReceive 메서드를 실행합니다.
3. 역시나 LoopReceive메서드 블럭없이 동작하기에 바로 다음 loopAccept 메서드가 반복됩니다.
4. LoopReceive는 클라이언트에서 자료를 보냈을때 완료되고 다음 loopReceive를 반복합니다.
문제점
.1 클라이언트를 5~6개 이상실행하였다가 종료하면 ,메인스레드이외에 작업스레드가 여러개 생기는데 어디서 잘못된건지 모르겠습니다.
.2 loopReceive 메서드에서 beginReceive로 기다리는 동작을 실행하는데. 클라이언트에서 소켓을 종료하게 되면 해당 메서드는 사라지지 않는건지 궁금합니다.
public async Task<bool> Start()
{
if (!CheckSocketStart())
{
return false;
}
LocalSocket = GetTcpSocket();
LocalSocket.Bind(LocalSocketIpEndPoint);
LocalSocket.Listen(5);
ActSysMessage?.Invoke("서버시작");
LoopAccept();
return true;
}
/// <summary>
/// 클라이언트의 접속을 기다리고 접속이 처리되면 반복적으로 처리
/// </summary>
/// <returns></returns>
private void LoopAccept()
{
var awaiter = AcceptTaskCompletionSource(LocalSocket).GetAwaiter();
awaiter.OnCompleted(() => {
var client = awaiter.GetResult();
_sockets.Add(client);
LoopReceive(client);
LoopAccept();
});
}
/// <summary>
/// Socket의 beginAccept가 완료되면 endAccept로 완료처리를 하고 client를
/// TaskCompletionSource를 통해서 전달함 block을 사용하지 않는게 목표.
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public Task<Socket> AcceptTaskCompletionSource (Socket socket)
{
var tcs = new TaskCompletionSource<Socket>(socket);
socket.BeginAccept(a => {
try
{
var retsocket= a.AsyncState as Socket;
var client = retsocket.EndAccept(a);
tcs.SetResult(client);
}
catch (Exception e)
{
tcs.SetException(e);
}
}, socket);
return tcs.Task;
}
///반복적으로 데이터를 받는 부분.
private void LoopReceive( Socket socket)
{
if (socket == null || !socket.Connected)
{
return;
}
var awaiter = ReceiveTaskCompletionSource(socket).GetAwaiter();
awaiter.OnCompleted(() => {
var ret = awaiter.GetResult();
if (ret ==null || ret.Length == 0)
{
return;
}
string recv = Encoding.UTF8.GetString(ret);
ActReceiveMessage?.Invoke(recv);
LoopReceive(socket);
});
}
/// <summary>
/// beginReceive가 완료되면 endReceive로 완료처리를 한후에 TaskCompletionSource를 통해서
/// 받은 데이터를 전송함.
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public Task<Byte[]> ReceiveTaskCompletionSource (Socket socket)
{
if (socket == null || !socket.Connected)
{
return null;
}
var tcs = new TaskCompletionSource<Byte[]>(socket);
var buffer = new byte[1024];
socket.BeginReceive(buffer, 0, 1024, SocketFlags.None, ar => {
try
{
var ret = ar.AsyncState as Socket;
int retcnt = ret.EndReceive(ar);
var retbuffer = new byte[retcnt];
Buffer.BlockCopy(buffer, 0, retbuffer, 0, retcnt);
tcs.SetResult(retbuffer);
}
catch (Exception er)
{
tcs.SetException(er);
}
}, socket);
return tcs.Task;
}
[최초 등록일: ]
[최종 수정일: 8/14/2018]