Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- leetcode
- 완전탐색
- 프로그래머스
- Algorithm
- 알고리즘
- 백트래킹
- JavaScript
- BFS
- 메모리 배리어
- 문자열&연산자
- 자바스크립트
- MemoryBarrier
- socket
- 제로베이스
- N과 M(2)
- dfs
- 코딩테스트 스터디
- c#
- 구현
- 구조체
- Server
- 멀티스레드
- 코딩테스트
- C++
- React
- map
- 백준
- 제로베이스 프론트엔드 스쿨
- 프론트엔드 스쿨
- 서버
Archives
- Today
- Total
Written
소켓 프로그래밍 #2 본문
비동기로 구현하기
사실상 bloking 방식의 코드가 실제로 현업에서 쓰일일은 거의 없다고 봐도 무방하다.
#1은 단순히 소켓 통신이 무엇인지에 대한 이해를 위한 코드였고, 실제로는 언제 통신이 발생할지 모르기 때문에 non-blocking 계열의 함수들을 사용하여 소켓 통신을 구현해야한다.
=> Listener라는 클래스를 새로 만들어 코드의 분리 시작. 서버 측 소켓의 동작들을 비동기 로직을 포함하여 구현해둔 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
class Listener
{
//소켓 생성 코드를 분리시키기 위한 작업
Socket _listenSocket;
//Action은 반환값이 없는 인자만 존재하는 delegate
Action<Socket> _onAcceptHandler;
//소켓 생성을 위해 EndPoint가 필요하기 때문에 인자로 받는다
public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
{
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_onAcceptHandler += onAcceptHandler;
//소켓을 생성했으니 EndPoint와 연결(Bind) + 대기(Listen)진행
_listenSocket.Bind(endPoint);
_listenSocket.Listen(10);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
RegisterAccept(args);
}
//비동기 방식으로 Accept를 처리해줘야함. Blocking방식은 한계가 많음.
//비동기 방식으로 Accept를 완료했을 때, 콜백함수를 실행시켜 그 후의 동작들을 설계하자.
//그렇다면 SocketAsyncEventArgs는 무엇이냐 ? -> 비동기 방식으로 동작하는 소켓의 로직들을 이벤트 형식으로 사용할수 있게 도와주는 클래스
public void RegisterAccept(SocketAsyncEventArgs args)
{
//null로 밀어주는 이유는 그전의 통신으로 인해 AcceptSocket에 데이터가 이미 사용했던 저장되어 있기 때문!
args.AcceptSocket = null;
bool pending = _listenSocket.AcceptAsync(args);
if (pending == false) //pending이 true면 대기하다 Accept가 실행될때,이벤트를 통해 콜백을 실행시켜주겠단 뜻
{
OnAcceptCompleted(null,args);
}
}
public void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
//connect과 Accept가 성공했을 때, 하고 싶은 동작들을 여기에 구현하는것.
if(args.SocketError == SocketError.Success)
{
//TODO
//여기선 뭘해야하냐 -> Accept까지 이루어졌으니 Recv Send의 과정이 들어가야겠지.
//Recv와 Send를 어떻게 구현할지 생각해보기.
//onAcceptHandler에 Accept이후 해야 할 것들을 담아두고, 여기서 Invoke를 통해 동작시키기.
_onAcceptHandler.Invoke(args.AcceptSocket); //onAcceptHandler가 Socket을 인자로 받으니까 AcceptSocket으로 Socket을 뱉어주고 있다.
}
else
{
Console.WriteLine(args.SocketError.ToString());
}
//하나의 통신이 성공했으니, 다음 통신을 위해 Accept를 다시 예약해줌.
RegisterAccept(args);
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
static Listener _listener = new Listener();
static void OnAcceptHandler(Socket clientSocket)
{
try
{
//받기와 보내기 Recv와 Send
//받으려면 받아낼 바구니가 필요함. 그 바구니가 RecvBuff다!
//Receive함수가 int를 반환한다 -> 몇 바이트를 받았는지 리턴해줌.
byte[] recvBuff = new byte[1024];
int recvBytes = clientSocket.Receive(recvBuff);
//클라에서 보낸 문자열 데이터가 recvBuff에 들어갈때 byte 배열로 들어갔는데, 그걸 다시 문자열로 복원해주는 함수
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Client : {recvData}");
//보낸다 -> 문자열을 Bytes로 변환해주는 함수를 통해 sendBuff에 저장함
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome MMO SERVER");
clientSocket.Send(sendBuff);
//연결 종료.
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
static void Main(string[] args)
{
//Socket은 인자를 넘겨줘야함. IP주소 , TCP인지UDP인지 정해줘야함
//Dns사용
string host = Dns.GetHostName(); //내 IP 추출
IPHostEntry ipHost = Dns.GetHostEntry(host);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
_listener.Init(endPoint,OnAcceptHandler);
Console.WriteLine("Listening...");
while (true)
{
;
}
}
|
cs |
'Server > 소켓' 카테고리의 다른 글
소켓 프로그래밍 #1 (0) | 2023.07.12 |
---|
Comments