다중 프로세스 디버깅 : https://learn.microsoft.com/ko-kr/visualstudio/debugger/debug-multiple-processes?view=vs-2022
다중 스레드 디버깅 : https://learn.microsoft.com/ko-kr/visualstudio/debugger/debug-multithreaded-applications-in-visual-studio?view=vs-2022
공식 문서에 따르면 local address를 socket에 연결하는 함수
3 way handshake를 통해 socket 구조체를 채우는데 bind를 통해 local 정보를 추가하는 듯
이를 증명하기 위해 만약 client socket을 bind를 통해 생성한다면 client socket은 이 때 지정된 port번호를 통해 통신하게 됨
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
{
SOCKADDR_IN sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("192.168.0.126");
sa.sin_port = htons(20000);
{
int ret = bind(clientSocket, (sockaddr*)&sa, sizeof(sa));
if (ret == SOCKET_ERROR)
{
WSACleanup();
return 1;
}
}
}
SOCKADDR_IN sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("192.168.0.126");
sa.sin_port = htons(10000);
{
int ret = connect(clientSocket, (sockaddr*)&sa, sizeof(sa));
if (ret == SOCKET_ERROR)
{
printf("%d", WSAGetLastError());
WSACleanup();
return 1;
}
}
Bind에 대한 자세한 설명
socket 재사용의 실질적인 예에서 시작한 의문으로 위 사이트를 발견
SockAddr_in.sin_addr을 client에서는 통신하길 희망하는 host로, Server는 htonl(INADDR_ANY)를 통해 요청이 들어오는 모든 host와 통신하는 것과 위 사이트에서 socket discriptor와 unix는 모든 것을 file로 취급한다는 이야기가 떠올라 그렇다면 socket이란 통신하고자 하는 host를 지정하는 file이 아닐까라는 가정을 세웠고, bind함수는 통신하고자 하는 외부 host를 지정하는 함수라고 가정하였음
그렇다면 client의 connect()는 내부적으로 bind를 호출하고 3 way handshake만 수행하는 게 아닐까라는 생각에 이런저런 조사를 수행하게 되었음
결론적으로 이야기하자면 bind는 결국 그냥 local data를 채우는 함수였다.. 뭐 그런 이야기
Windows의 에러코드를 문자열로 변환하는 함수
연결 요청을 받아 queue에 저장하는 함수
backlog는 queue의 크기
최대 연결 socket 개수는 "ulimit -a"를 통해 알 수 있음(리눅스)
윈도우에서의 이론상 최대 소쳇 접속 수는 16,000,000개정도라고 함
Unicast : 1인에게 데이터 전송
Braodcast : 네트워크 내 모든 host에게 전송
Multicast : 지정된 집단에게 데이터 전송
socket의 설정을 수정, 확인하는 함수
SO_linger, SO_reuseaddr, IPProto_tcp 등 다양함
socket 재사용 옵션
TCP는 연결 해제 시 4 way handshake를 사용하는데 연결 해제를 확실하게 수행하기 위해 socket이 time-wait상태에 들어갈 수 있음
이러한 상황에서 바로 해당 socket을 사용하려 할 시 이미 사용중이므로 사용이 불가능
이러한 문제를 해결하고 socket을 바로 재사용 할 수 있도록 설정하는 옵션
일반적으로 server side socket에서 사용한다고 함
다만, client side socket에서 사용 시 효과가 없다고 하는데 정확한 상황은 아직 잘 모르겠음
TCP에서 데이터를 전송할 경우 데이터 크기가 너무 작다면 늦더라도 모아서 보내는 경우가 있음
다만, Game환경에서는 key입력같은 작은 데이터를 수시로 전송할텐데, 이를 모아서 받는 경우 지연으로 인한 문제가 발생할 수 있음
이를 방지할 수 있는 옵션
shutdown과 socketclose가 있음
creationFlag를 통해 생성 즉시 Thread가 수행되는 것을 막을 수 있음
이상적으로는 return을 통해 쓰레드가 소멸하는 것이 좋으나 Server의 Listen같이 무한루프로 작동하는 Thread의 경우 강제로 소멸시키는 것이 필요하기도 함
Thread 자신이 직접 종료
Thread가 사용한 DLL도 해제
stack도 해제하는가?
Thread 외부에서 강제 종료
DLL 해제를 책임지지 않음
Thread 일시 정지, 재개
현재 수행중인 Thread 식별 코드
Thread는 각각 고유의 stack을 가지므로 지역변수는 stack별로 고유
다만, 전역변수와 정적 변수는 프로세스 내의 모든 Thread가 공유
또한, 지역변수는 데이터를 장기 저장하기 힘듬
이러한 문제를 해결하기 위해 Thread마다 고유의 전역 변수 저장 공간을 제공하는 기법
#pragma pack(push, 1)
// define data
#pragma pack(pop)
Padding bit를 제거하여 Network상에서 전송할 데이터의 크기를 줄이고 Deserialize시의 계산 복잡성을 줄일 수 있는 듯
다만, 이를 해제하지 않을 경우 데이터를 읽는 속도에서 손해를 볼 수 있음
Socket send buffer가 가득차있거나 통신 상태로인해 데이터를 완전히 전송하지 못하는 경우가 있음
Send buffer에 들어가있다면 통신이 느린 정도로는 언젠가는 전송을 성공하겠지만, 만약 Buffer의 여유공간보다 더 큰 데이터를 Send할 경우 Send()는 데이터의 일부만을 send buffer에 옮겨놓음
이 문제를 해결하기 위해 send()역시 recv()와 마찬가지로 데이터를 모두 buffer로 옮길 수 있도록 코드를 변경해야 함