네트워크 코어는 TCP/IP 네트워크를 연결하고, 연결한 네트워크를 통해 주고받을 패킷의 처리 방식에 대한 코어 시스템을 구현해놓은 라이브러리이다.
서버뿐 아니라 클라이언트의 네트워크 연결 또한 네트워크 코어 라이브러리를 이용한다.
각각 다음 클래스들로 나뉘어져 있다.
서버에서 사용하는 소켓 연결 클래스이다. 다량의 클라이언트와 동시에 연결해야 하므로 많은 소켓을 열어둔다.
하나의 클라이언트에 연결이 성공했을 시 그 클라이언트에 대응되는 세션을 하나 만들어 할당해준다.
스도코드
클래스 Listener
{
멤버 변수:
- _lock: 멀티스레드 동기화를 위한 객체
- _listenSocket: 클라이언트 연결을 수락할 소켓
- _sessionFactory: 세션을 생성하는 함수
- _acceptArgs: 비동기 연결 수락을 위한 SocketAsyncEventArgs 객체
메서드:
- Start(IPEndPoint endPoint, Func<Session> sessionFactory):
- _sessionFactory를 설정
- _listenSocket을 생성 및 바인딩하여 대기 상태로 설정
- RegisterAccept()를 호출하여 클라이언트 연결을 수락
- RegisterAccept():
- _acceptArgs를 초기화하고 비동기 Accept 시도
- Accept가 즉시 완료되면 OnAcceptCompleted 실행
- OnAcceptCompleted(object sender, SocketAsyncEventArgs args):
- 연결이 성공하면:
- 세션 객체를 생성하고 Start 호출
- RegisterAccept()를 다시 호출하여 다음 클라이언트 대기
- 실패 시 RegisterAccept()를 다시 호출하여 대기
- Stop():
- _listenSocket이 존재하면 닫고 정리
}
클라이언트에서 사용하는 소켓 연결 클래스이다. 서버 하나와만 통신하므로 하나의 소켓을 열어둔다.
서버와의 연결을 성공하면 서버 세션을 하나 만들어 할당해준다.
스도코드
클래스 Connector
{
멤버 변수:
- _sessionFactory: 세션을 생성하는 함수
메서드:
- Connect(IPEndPoint endPoint, Func<Session> sessionFactory, int count = 1):
- count 만큼 반복하여 소켓을 생성하고 연결 시도
- RegisterConnect()를 호출하여 비동기 연결 요청
- RegisterConnect(SocketAsyncEventArgs args):
- 비동기 연결 요청 수행
- 요청이 즉시 완료되면 OnConnectCompleted 실행
- OnConnectCompleted(object sender, SocketAsyncEventArgs args):
- 연결이 성공하면:
- 세션을 생성하고 Start 호출
- OnConnected 실행
- 실패 시 오류 출력
}
서버와 클라이언트에서 주고받는 패킷들을 처리하기 전에 임시로 저장해두는 버퍼 클래스.
바이트 배열 형식의 버퍼와 이를 읽고 쓰는데 도움을 주는 유틸리티 함수들로 되어 있다.
스도코드
클래스 RecvBuffer
{
멤버 변수:
- _buffer: 데이터 저장용 버퍼 (ArraySegment<byte>)
- _readPos: 읽기 위치 커서
- _writePos: 쓰기 위치 커서
속성:
- DataSize: 현재 버퍼에 저장된 데이터 크기
- FreeSize: 버퍼에 남은 공간 크기
- ReadSegment: 현재 읽을 수 있는 데이터 범위 (ArraySegment<byte>)
- WriteSegment: 데이터를 받을 수 있는 범위 (ArraySegment<byte>)
메서드:
- RecvBuffer(int bufferSize):
- 버퍼를 bufferSize 크기로 초기화
- Clean():
- 데이터가 없으면 커서를 초기화
- 데이터가 남아 있으면 앞으로 이동하여 정리
- OnRead(int numOfBytes):
- numOfBytes만큼 읽기 커서를 이동
- 유효성 검사 후 성공 여부 반환
- OnWrite(int numOfBytes):
- numOfBytes만큼 쓰기 커서를 이동
- 유효성 검사 후 성공 여부 반환
}
세션 클래스는 네트워크에 연결되어 있는 각 객체들의 상태를 저장 및 변경하는 클래스이다.
스도코드
클래스 Session (추상 클래스)
{
멤버 변수:
- _socket: 연결된 클라이언트 소켓
- _disconnected: 연결 상태를 나타내는 플래그
- _lock: 멀티스레드 동기화를 위한 객체
- _sendQueue: 전송할 데이터를 저장하는 큐
- _pendingList: 현재 전송 중인 데이터 리스트
- _sendArgs: 비동기 전송을 위한 SocketAsyncEventArgs
- _recvArgs: 비동기 수신을 위한 SocketAsyncEventArgs
- _recvBuffer: 수신 데이터를 저장할 RecvBuffer 객체
#region 가상 함수들
- OnConnected(EndPoint endPoint): 클라이언트가 연결될 때 호출되는 함수
- OnRecv(ArraySegment<byte> buffer): 데이터를 받을 때 실행되는 함수 (리턴값: 처리한 데이터 크기)
- OnSend(int numOfBytes): 데이터를 성공적으로 전송했을 때 호출되는 함수
- OnDisconnected(EndPoint endPoint): 클라이언트 연결이 종료될 때 호출되는 함수
#endregion
메서드:
- Clear():
- _sendQueue와 _pendingList를 초기화
- Start(Socket socket):
- _socket 할당 및 이벤트 핸들러 등록
- 수신 시작 (RegisterRecv 호출)
- Send(List<ArraySegment<byte>> sendBuffList):
- 데이터가 존재하지 않으면 반환
- sendBuffList의 데이터를 _sendQueue에 추가
- _pendingList가 비어 있다면 RegisterSend 호출
- Send(ArraySegment<byte> sendBuff):
- _sendQueue에 데이터 추가
- _pendingList가 비어 있다면 RegisterSend 호출
- Disconnect():
- 이미 연결이 종료되었으면 반환
- OnDisconnected 호출 후 소켓 종료
- Clear() 실행하여 내부 데이터 정리
#region 네트워크 통신
- RegisterSend():
- 연결이 종료되었으면 반환
- _sendQueue에서 데이터를 꺼내 _pendingList에 추가
- _sendArgs에 데이터 설정 후 비동기 전송 시도
- 만약 전송이 즉시 완료되었다면 OnSendCompleted 실행
- OnSendCompleted(object sender, SocketAsyncEventArgs args):
- 전송이 성공하면:
- _pendingList 초기화
- OnSend 호출
- _sendQueue에 남은 데이터가 있으면 RegisterSend 호출
- 전송 실패 시 Disconnect 실행
- RegisterRecv():
- 연결이 종료되었으면 반환
- _recvBuffer의 버퍼를 초기화하고 비동기 수신 요청
- 요청이 즉시 완료되면 OnRecvCompleted 실행
- OnRecvCompleted(object sender, SocketAsyncEventArgs args):
- 데이터 수신이 성공하면:
- _recvBuffer의 Write 커서를 이동
- OnRecv을 호출하여 데이터를 처리한 크기를 받아옴
- 데이터가 잘못 처리되었으면 Disconnect 실행
- Read 커서를 이동한 후 RegisterRecv 재호출
- 데이터 수신이 실패하면 Disconnect 실행
#endregion
}