/* --소켓 데이터 송신 함수-- */ static void SendCall(IAsyncResult iar) { // 강제로 Client 종료시 프로그램 사망을 방지하기 위하여 try catch문을 사용 try { // 개별 핸들러(클라이언트)의 상태 인스턴스 받아오기 BSstateBuffer state = (BSstateBuffer)iar.AsyncState; // 디버그 로그 콘솔에 출력 Console.WriteLine(state.clientCounter + " 번 클라이언트로 데이터를 송신하는 중...\n"); // 데이터 송신 int sendSize = workingSocket[state.clientCounter].EndSend(iar); Console.WriteLine("보낸 데이터 크기 -> " + sendSize + "\n"); // 송수신 함수 스레드 계속 진행하도록 허락해 계속 송수신 처리 sendAllDone[state.clientCounter].Set(); } catch (Exception exc) { Console.WriteLine("데이터 송신 실패...\n" + exc + "\n"); return; } }
public static byte[] sendBuffer = new byte[1024]; // 보낼 데이터 저장용 버퍼 정의 /* --소켓 연결 함수-- */ static void AcceptCall(IAsyncResult iar) { // 강제로 Client 종료시 프로그램 사망을 방지하기 위하여 try catch문을 사용 try { Console.WriteLine("연결을 승인하는 중...\n"); // 리스너(서버), 핸들러(클라이언트) 소켓 정의하고 연결 승인 Socket listenerSocket = (Socket)iar.AsyncState; Socket handlerSocket = listenerSocket.EndAccept(iar); // 개별 핸들러(클라이언트)의 상태 인스턴스 생성 BSstateBuffer state = new BSstateBuffer(); // 송수신 스레드 동기화 리스트 추가 sendAllDone.Add(new ManualResetEvent(false)); // 핸들러(클라이언트) 소켓을 추후 송수신에 사용을 위해 전역 변수를 리스트에 추가 workingSocket.Add(handlerSocket); // 수신용 데이터 저장용 전역 변수를 리스트에 추가 clientDataList.Add(new BSclientData()); // 몇번째 클라이언트(리스트)인지 카운트 저장 state.clientCounter = workingSocket.Count - 1; // 클라이언트 연결정보 표시 string clientAddress = workingSocket[state.clientCounter].RemoteEndPoint.ToString(); // 클라이언트 IP, Port 가져오기 (예시 123.123.123.123:1234) Console.WriteLine(state.clientCounter + " 번 클라이언트 연결됨 -> " + clientAddress + "\n"); // 메인 함수 스레드 계속 진행하도록 허락해 다음 클라이언트 연결 계속 받기 serverAllDone.Set(); // 클라이언트에 데이터 송수신 계속 시도 while (true) { // 클라이언트와 이미 송수신 중이기 때문에 송수신 함수 스레드 일시중지 sendAllDone[state.clientCounter].Reset(); // 데이터 수신 시작 workingSocket[state.clientCounter].BeginReceive(state.receiveBuffer, 0, state.receiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCall), state); // 여유 대기시간 Thread.Sleep(200); // 클라이언트가 연결 종료 요청을 보낸경우 소켓 리스트 비우고 연결 스레드 종료 if (clientDataList[state.clientCounter].exitConnection == "T") { workingSocket.RemoveAt(state.clientCounter); // 해당 클라이언트 번호의 소켓 데이터 제거 clientDataList.RemoveAt(state.clientCounter); // 해당 클라이언트 번호의 클라이언트 데이터 제거 break; } // 클라이언트와 이미 송수신 중인지 확인하고 송수신 함수 스레드 계속 진행 sendAllDone[state.clientCounter].WaitOne(); } } catch (Exception exc) // 예외사항 발생시 연결 종료 { Console.WriteLine("클라이언트와 연결 실패...\n" + exc); return; } }
/* --소켓 데이터 수신 함수-- */ static void ReceiveCall(IAsyncResult iar) { // 강제로 Client 종료시 프로그램 사망을 방지하기 위하여 try catch문을 사용 try { // 개별 핸들러(클라이언트)의 상태 인스턴스 받아오기 BSstateBuffer state = (BSstateBuffer)iar.AsyncState; // 디버그 로그 콘솔에 출력 Console.WriteLine(state.clientCounter + " 번 클라이언트로 부터 데이터를 수신받는 중...\n"); // 핸들러(클라이언트) 소켓을 통해 데이터 수신받고 사이즈 저장 int receiveSize = workingSocket[state.clientCounter].EndReceive(iar); // 받을 데이터가 있는지 확인 (데이터 길이가 0보다 크면) if (receiveSize > 0) { // 만약 마지막으로 받은 버퍼에서 EOF(문장의 끝)을 발견하지 못한 경우 데이터 계속 받음 if (state.receiveBuffer[state.receiveBuffer.Length - 1] != '\0') { // 데이터가 아직 다 수신되지 않았기 때문에 계속 호출하여 받아야함 workingSocket[state.clientCounter].BeginReceive(state.receiveBuffer, 0, state.receiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCall), state); } else // 데이터가 다 수신되었음 { // 버퍼의 내용을 수신 데이터 변수에 저장 state.receiveData = Encoding.UTF8.GetString(state.receiveBuffer, 0, receiveSize); Console.WriteLine("받은 데이터 -> " + state.receiveData + "\n"); // 받은 메세지 | 단위로 잘라서 저장 // receiveData = "MAC address | Exit Connection? | Nick name | UFO position | UFO velocity | UFO rotation | Hitted UFO | My bullet position + Velocity + Remaining time..." string[] receiveSplitData = state.receiveData.Split('|'); // 받은 데이터를 요소별로 잘라서 저장한 배열 정의 Console.WriteLine("자른 데이터는 ->\n"); // 자른 메세지 표시 & BSclientData 클래스 형태로 저장 for (int countRec = 0; countRec < receiveSplitData.Length; countRec++) { Console.WriteLine(receiveSplitData[countRec]); switch (countRec) { case 0: clientDataList[state.clientCounter].macAddress = receiveSplitData[0].ToString(); break; case 1: clientDataList[state.clientCounter].exitConnection = receiveSplitData[1].ToString(); break; case 2: clientDataList[state.clientCounter].nickName = receiveSplitData[2].ToString(); break; case 3: clientDataList[state.clientCounter].ufoPosition = receiveSplitData[3].ToString(); break; case 4: clientDataList[state.clientCounter].ufoVelocity = receiveSplitData[4].ToString(); break; case 5: clientDataList[state.clientCounter].ufoRotation = receiveSplitData[5].ToString(); break; case 6: // 다시 때린 UFO 맥 어드레스 데이터 분할하여 저장 string[] receiveSplitHittedUfoMac = receiveSplitData[6].Split('+'); // 해당 클라이언트가 때린 UFO 맥 어드레스 데이터를 배열로 전부 저장 for (int countHitUfo = 0; countHitUfo < receiveSplitHittedUfoMac.Length; countHitUfo++) { clientDataList[state.clientCounter].hittedUfoMac[countHitUfo] = receiveSplitHittedUfoMac[countHitUfo].ToString(); } break; case 7: // 다시 총알 데이터 분할하여 저장 string[] receiveSplitBullet = receiveSplitData[7].Split('+'); // 총알의 위치, 벡터, 생명시간 3가지의 요소를 각각의 총알 리스트로 저장 for (int countBul = 0; countBul <= (receiveSplitBullet.Length - 3); countBul += 3) { clientDataList[state.clientCounter].bullet[countBul / 3].position = receiveSplitBullet[countBul].ToString(); clientDataList[state.clientCounter].bullet[countBul / 3].velocity = receiveSplitBullet[countBul + 1].ToString(); clientDataList[state.clientCounter].bullet[countBul / 3].remainingTime = receiveSplitBullet[countBul + 2].ToString(); } break; } } // 송신용 데이터 조합 CollectSendData(state.clientCounter); // 수신이 끝났으니 이제 데이터 송신 workingSocket[state.clientCounter].BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(SendCall), state); } } else { // 수신받을 데이터가 없으면 수신 종료 Console.WriteLine(state.clientCounter + " 번 클라이언트로 부터 수신받을 데이터 없음...\n"); } } catch (Exception exc) { Console.WriteLine("데이터 수신 실패...\n" + exc); return; } }