/// <summary> /// 데이터 수신시 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ReceiveCompleted(object sender, SocketAsyncEventArgs e) { // 클라이언트 소켓 얻어오기 및 뷰어 얻어오기 Socket clientSock = sender as Socket; Viewer viewer = findViewerBySocket(clientSock, Viewers); // 소켓 데이터 SocketData data = e.UserToken as SocketData; if (viewer != null) { viewer.LastConnected = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; } try { if (clientSock.Connected && e.BytesTransferred > 0) { data.Data = e.Buffer; // 인증 처리 if (!viewer.Authorized) { if (data.Code == NET_START) { viewer.Authorized = true; logln($"클라이언트 {viewer.Socket.RemoteEndPoint.ToString()} 인증됨.", true); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.SetBuffer(UTF8.GetBytes(NET_START), 0, 8); clientSock.SendAsync(args); } } else if (viewer.Authorized && !viewer.LoggedIn) { // 로그인 처리 if (data.Code == NET_LOGIN) { int pnSize = BitConverter.ToInt32(data.Data, 8); string paneNumber = UTF8.GetString(data.Data, 12, pnSize).Replace("\0", ""); int nickSize = BitConverter.ToInt32(data.Data, 12 + pnSize); string nick = UTF8.GetString(data.Data, 12 + pnSize + 4, nickSize); nick = nick.Replace("\0", "").Trim(); logln($"클라이언트 {viewer.Socket.RemoteEndPoint.ToString()} 로그인 중...", true); viewer.PaneNumber = paneNumber; viewer.IpAddr = getIPAddress(BitConverter.ToUInt32(((IPEndPoint)viewer.Socket.RemoteEndPoint).Address.GetAddressBytes(), 0)); viewer.Nick = nick; viewer.LoggedIn = true; logln("로그인 성공!\n" + $"PaneNumber: {paneNumber}\n" + $"IpAddr: {viewer.IpAddr}\n" + $"Nick: {viewer.Nick}", true); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); byte[] arr = new byte[9]; UTF8.GetBytes(NET_LOGIN).CopyTo(arr, 0); arr[8] = 0x01; args.SetBuffer(arr, 0, 9); clientSock.SendAsync(args); } } // 채팅 처리 if (viewer.Authorized && viewer.LoggedIn) { switch (data.Code) { // 방 리스트 전송 case NET_ROOM_LIST: { SendRoomList(Rooms, viewer); break; } // 방 입장 처리 case NET_ROOM_ENTER: { EnterRoom(Rooms, viewer, data); break; } // 방 퇴장 처리 case NET_ROOM_EXIT: try { LeaveRoom(viewer, Rooms); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); byte[] arr = new byte[9]; UTF8.GetBytes(NET_ROOM_EXIT).CopyTo(arr, 0); arr[9] = 0x01; args.SetBuffer(arr, 0, 9); clientSock.SendAsync(args); } catch (Exception ee) { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); byte[] arr = new byte[5]; UTF8.GetBytes(NET_ROOM_EXIT).CopyTo(arr, 0); arr[9] = 0xFF; args.SetBuffer(arr, 0, 9); clientSock.SendAsync(args); logln($"{viewer.Nick}({viewer.IpAddr})님께서 {findRoomByPaneNumber(viewer.PaneNumber, Rooms).RoomID}번 방에서 퇴장 중에 알 수 없는 에러 발생:\n{ee.ToString()}"); } break; // 방 생성 처리 case NET_ROOM_CREATE: { try { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(UTF8.GetBytes(NET_ROOM_CREATE)); if (!Utility.IsRoomExists(viewer.PaneNumber, Rooms)) { RoomInfo Room = new RoomInfo(); Room.PaneNumber = viewer.PaneNumber; Room.CreatedAt = DateTime.Now; Room.Owner = viewer; Rooms.Add(Room); writer.Write((byte)0x01); //logln($"{viewer.Nick}({viewer.IpAddr})에서 방 생성 요청 수락됨", true); } else { writer.Write((byte)0xFF); } args.SetBuffer(stream.ToArray(), 0, stream.ToArray().Length); stream = new MemoryStream(); writer = new BinaryWriter(stream); clientSock.SendAsync(args); break; } catch (Exception ee) { logln(ee.ToString(), true, true); break; } break; } case NET_ROOM_KICK: { int paneLen = BitConverter.ToInt32(data.Data, 8); string panenumber = UTF8.GetString(data.Data, 12, paneLen); Viewer target = findViewerByPaneNumber(panenumber, findRoomByPaneNumber(viewer.PaneNumber, Rooms)?.Viewer); try { if (target != null) { SystemRoom(viewer.RoomInfo, $"{target.Nick}<{target.PaneNumber}>님이 추방되었습니다."); MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(target.PaneBytes.Length); writer.Write(target.PaneBytes); writer.Write(UTF8.GetBytes(target.Nick).Length); writer.Write(UTF8.GetBytes(target.Nick)); writer.Write(UTF8.GetBytes(target.IpAddr).Length); writer.Write(UTF8.GetBytes(target.IpAddr)); BroadcastRoom(NET_ROOM_KICK, viewer.RoomInfo, stream.ToArray()); LeaveRoom(target, Rooms); } } catch (Exception ee) { Console.WriteLine(ee.ToString()); } break; } case NET_ROOM_DESTROY: { int lenPane = BitConverter.ToInt32(data.Data, 8); string pane = UTF8.GetString(data.Data, 12, lenPane); MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(lenPane); writer.Write(UTF8.GetBytes(pane)); writer.Write((byte)0x01); BroadcastMessage(NET_ROOM_DESTROY, Rooms, stream.ToArray()); DestroyRoom(pane, Rooms); break; } case NET_CHAT_MESSAGE: { if (viewer.RoomInfo != null) { int chatLen = BitConverter.ToInt32(data.Data, 8); string chat = UTF8.GetString(data.Data, 12, chatLen); chat = chat.Replace("\0", "").Trim(); RoomChatMsg(viewer, chat); RoomInfo curRoom = viewer.RoomInfo; MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(UTF8.GetByteCount(curRoom.PaneNumber)); writer.Write(UTF8.GetBytes(curRoom.PaneNumber)); BroadcastMessage(NET_PUSH_NEWMSG, Rooms, stream.ToArray()); } break; } case NET_CHAT_NOTICE: { int type = BitConverter.ToInt32(data.Data, 8); int lenPane = BitConverter.ToInt32(data.Data, 12); string paneNumber = UTF8.GetString(data.Data, 16, lenPane); int lenNotice = BitConverter.ToInt32(data.Data, 16 + lenPane); string notice = UTF8.GetString(data.Data, 20 + lenPane, lenNotice); if (type == 1) { NotifyAll(Rooms, notice); } else if (type == 2) { var room = findRoomByPaneNumber(paneNumber, Rooms); NotifyRoom(room, notice); } break; } case NET_LOGOUT: { LeaveRoom(viewer, Rooms); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.SetBuffer(UTF8.GetBytes(NET_LOGOUT), 0, 8); viewer.Socket.SendAsync(args); break; } } } data = new SocketData(); data.initData(1024); e.SetBuffer(data.Data, 0, 1024); clientSock.ReceiveAsync(e); } //else //{ // // 연결 끊김 처리 // logln($"클라이언트 {clientSock.RemoteEndPoint.ToString()}의 연결이 끊겼습니다.", true); // clientSock.Disconnect(false); // clientSock.Close(); // clientSock.Dispose(); // Viewer remove = null; // foreach (Viewer v in Viewers) // { // if (v.Socket == clientSock) // { // remove = v; // break; // } // } // Viewers.Remove(remove); //} } catch (SocketException ee) { logln($"소켓 에러\n{ee.ToString()}"); } catch (Exception ee) { logln($"알 수 없는 에러\n{ee.ToString()}"); } }
/// <summary> /// 방 리스트에서 해당 방이 몇 번째 요소에 있는지 알아냄 /// </summary> /// <param name="Room">방</param> /// <param name="Rooms">방 리스트</param> /// <returns></returns> public static int getRoomIdByRoom(RoomInfo Room, List<RoomInfo> Rooms) { for (int i = 0; i < Rooms.Count; i++) { if (Rooms[i].PaneNumber == Room.PaneNumber) { return i; } } return -1; }
/// <summary> /// 특정 방 모두에게 코드 송신 /// </summary> /// <param name="message">코드</param> /// <param name="room">방</param> /// <param name="data">(선택)데이터</param> public static void BroadcastRoom(string message, RoomInfo room, byte[] data = null) { foreach (Viewer v in room.Viewer) { if (v.Socket.Connected) { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); stream.Write(UTF8.GetBytes(message), 0, 8); if (data != null) { stream.Write(data, 0, data.Length); } args.SetBuffer(stream.ToArray(), 0, stream.ToArray().Length); v.Socket.SendAsync(args); } } }
/// <summary> /// 해당 뷰어가 특정 방에 있는지 확인 /// </summary> /// <param name="viewer">뷰어</param> /// <param name="room">방</param> /// <returns></returns> public static bool IsViewerInRoom(Viewer viewer, RoomInfo room) { foreach (Viewer v in room.Viewer) { if (v.PaneNumber.Equals(viewer.PaneNumber)) { return true; } } return false; }
/// <summary> /// 방에 공지사항 띄우기 /// </summary> /// <param name="target">방</param> /// <param name="message">공지 문자열</param> public static void SystemRoom(RoomInfo target, string message) { if (target == null) { return; } foreach (Viewer v in target.Viewer) { try { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(UTF8.GetBytes(NET_CHAT_SYSTEM)); writer.Write(UTF8.GetBytes(message).Length); writer.Write(UTF8.GetBytes(message)); args.SetBuffer(stream.ToArray(), 0, stream.ToArray().Length); v.Socket.SendAsync(args); } catch (Exception e) { logln($"{target.RoomID}의 {v.Nick}({v.IpAddr})에게 시스템 메세지를 전송하는 중 에러 발생!\n{e.ToString()}", true); } } logln($"SYSTEM({target.RoomID}번 방): {message}", true); }