Coding Memo
[C#] SocketAsyncEventArgs.BufferList 참고사항 본문
[요약]
SocketAsyncEventArgs.BufferList을 통해 데이터를 전송 할 때, 반드시 새로운 리스트를 만들고 바이트 데이터를 그 리스트에 추가(Add)를 한 후에 그 리스트를 SocketAsyncEventArgs.BufferList에 직접 할당해야만 한다!!
(이 관련 내용은 공식적으로 문서화 되어있지 않다고 한다.)
1. 리스트 생성 (IList<ArraySegment<byte>>)
2. 1에서 생성한 리스트에 아이템 추가(Add)
3. SocketAsyncEventArgs.BufferList에 1에서 생성한 리스트 직접 할당
***SocketAsyncEventArgs.BufferList에 직접 아이템 Add 하지 말자.***
Why?
BufferList의 Setter 호출 시, 기존 리스트에 있는 버퍼만 사용하기 때문이다.
(즉, 이후 아이템을 추가해도 반영이 안된다는 것이다.)
C#의 System.Net.Sockets에 구현되어 있는 SocketAsyncEventArgs의 BufferList의 setter 코드를 보면 알 수 있는데, BufferList를 설정할 때 바이트 배열 참조를 복사하고 사용하는 WSABuffer[] 필드가 있는데 실제 전송하는 것은 이 배열 필드이기 떄문이다.
문제를 발견한 것은 AsyncSocketEventArgs.BufferList에 버퍼 데이터를 넣고 클라이언트나 서버로 데이터를 전송하려고 할 때였다.
다음의 코드는 문제가 없어 보인다.
단순히 이벤트의 버퍼리스트에 데이터를 추가하고 그것을 Send하는 코드이다.
public class Session
{
Socket _socket;
readonly List<Memory<byte>> _sendPendingList = new();
...
readonly SocketAsyncEventArgs _sendEvent = new();
...
void Send()
{
...
_sendEvent.BufferList = new List<ArraySegement<byte>>();
...
foreach (Memory<byte> buff in _sendPendingList)
{
if (MemoryMarshal.TryGetARray<byte>(buff, out var segment))
{
_sendEvent.BufferList.Add(segment);
}
}
...
_socket.SendAsync(_sendEvent);
}
}
하지만, 실제 전송을 하면 전송(SendAsync) 후, SocketError 필드에 SocketError.InvalidArgument가 들어가 있는 것을 확인 할 수 있다. 그리고 데이터를 받는 쪽에서도 아무 데이터를 받지 못한다.
무엇이 문제일까 공식 문서도 살펴보았다.
특별히 확인할 내용은 없었다.
해결은 위에 링크를 걸어둔 stackoverflow에서 답을 찾을 수 있었다.
따라서 코드를 다음과 같이 고쳤다.
public class Session
{
Socket _socket;
readonly List<Memory<byte>> _sendPendingList = new();
...
readonly SocketAsyncEventArgs _sendEvent = new();
...
void Send()
{
...
List<ArraySegement<byte>> list = new();
...
foreach (Memory<byte> buff in _sendPendingList)
{
if (MemoryMarshal.TryGetARray<byte>(buff, out var segment))
{
list.Add(segment);
}
}
// 직접 리스트 할당 (set)
_sendEvent.BufferList = list;
...
_socket.SendAsync(_sendEvent);
}
}
'Language > C#' 카테고리의 다른 글
[C#] lock (Monitor) (0) | 2023.08.08 |
---|---|
[C#] TCP 흐름제어 확인해보기 (0) | 2023.07.17 |
ThreadPool (SetMinThreads, SetMaxThreads) 주의사항 (0) | 2023.05.02 |
메소드 인자 전달 방법 (Method Parameters) (0) | 2023.05.02 |
매개변수 한정자 (ref, in, out) (0) | 2023.05.02 |