강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

Jaehyuk Lee님의 프로필 이미지
Jaehyuk Lee

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

SocketAsyncEventArgs.BufferList에 관해 질문

작성

·

86

·

수정됨

0

void RegisterSend()
{
	if (_disconnected == 1)
		return;

	while (_sendQueue.Count > 0)
	{
		ArraySegment<byte> buff = _sendQueue.Dequeue();
		_pendingList.Add(buff);
	}
	_sendArgs.BufferList = _pendingList;

	try
	{
		bool pending = _socket.SendAsync(_sendArgs);
		if (pending == false)
			OnSendCompleted(null, _sendArgs);
	}
	catch (Exception e)
	{
		Console.WriteLine($"RegisterSend Failed {e}");
	}
}

void OnSendCompleted(object sender, SocketAsyncEventArgs args)
{
	lock (_lock)
	{
		if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
		{
			try
			{
				_sendArgs.BufferList = null;
				_pendingList.Clear();

				OnSend(_sendArgs.BytesTransferred);

				if (_sendQueue.Count > 0)
					RegisterSend();
			}
			catch (Exception e)
			{
				Console.WriteLine($"OnSendCompleted Failed {e}");
			}
		}
		else
		{
			Disconnect();
		}
	}
}


해당 코드에 대한 질문이 있습니다.
RegisterSend에서 sendQueue에 있는 패킷들을 다 빼내서 pendingList에 넣고 pendingList를 args.BuffList로 설정합니다.

이후 OnSendComplete에 처리에 의문이 있습니다.
TCP 특성상 부분 전송이 이루어질 수 있다고 생각합니다.
부분 전송이 일어날 경우 확인을 안하고 pendingList.Clear해버리면 send패킷이 유실될 것 같습니다.
BufferList에 넣으면 SendAsync시에 c#에서 무조건 전송을 보장해주는건가요?
아니면 BufferList를 사용하지 말고 recv버퍼처럼 해야할 것 같다는 생각이 들어 질문합니다.
또한 BufferList에서 부분전송 체크할 방법이 있나요?

답변 2

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

이후 OnSendComplete에 처리에 의문이 있습니다.
TCP 특성상 부분 전송이 이루어질 수 있다고 생각합니다.
=> 아닙니다.
부분 전송은 TCP 단에서 내부적으로 일어나는 것이고
저 함수의 완료 처리가 되는 시점에서는, 이미 요청한 size가 다 전송된 것입니다.
C++의 네트워크 함수 또한 동일합니다.

0

안녕하세요, 인프런 AI 인턴입니다. Jaehyuk Lee님의 질문에 대해 답변 드리겠습니다.

먼저, 질문 주신 코드에서 RegisterSendOnSendCompleted의 작동 방식에 대해 설명드리겠습니다. C#의 SocketAsyncEventArgs.BufferList는 비동기 소켓 작업을 지원하기 위해 사용됩니다. 이는 여러 개의 버퍼를 하나의 리스트로 관리하여 전체 데이터를 한 번에 전송할 수 있도록 돕습니다. 중요한 포인트는, BufferList에 추가된 데이터는 SendAsync 메서드를 이용해 전송되며, 네트워크 레이어에서 자동으로 안전하게 처리됩니다.

  1. 전송 보장 여부: C#에서 제공되는 Socket.SendAsync 메서드는 실제로 네트워크 레이어에 맡겨 전송을 처리합니다. TCP의 경우, 데이터의 전송 순서와 안전성은 보장되지만, 버퍼의 크기 등 네트워크 상태의 영향으로 인해 한 번에 모든 데이터를 전송하지 못할 수도 있습니다.

  2. 부분 전송과 BufferList 초기화: OnSendCompleted에서 BytesTransferred를 검사하여 전송이 완료되었는지 확인할 수 있습니다. 부분 전송은 가능하지만, 각 SendAsync 호출은 전체 데이터 전송을 시도하며, 완료 콜백(OnSendCompleted)에서 이 데이터가 성공적으로 전송되었는지를 확인해야 합니다. 만약 데이터를 유실하는 것이 걱정된다면, BytesTransferred와 모든 데이터가 전송되었는지 직접 확인하고 조건부로 BufferList를 초기화하는 추가 로직을 고려해야 합니다.

  3. 부분 전송의 처리를 위한 조치: BufferListSendAsync 자체는 부분 전송 여부도 포함한 전송 상태를 관리합니다. 때문에 OnSendCompleted에서 BytesTransferred를 확인하고 필요한 경우 추가적인 처리를 진행하는 것이 중요합니다. 필요시, 데이터를 다시 전송할 수 있도록 재조정하는 로직을 구현하는 것도 가능합니다.

추가로, 이와 관련된 보다 깊은 이해를 원하신다면 아래의 유사 질문들을 참조하시기 바랍니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

Jaehyuk Lee님의 프로필 이미지
Jaehyuk Lee

작성한 질문수

질문하기