public void StartReceiving() { CruMessage[] receiveMsg = new CruMessage[50]; // 데이터를 받는 것은 언제나 열려있어야 한다. // 데이터를 받아서 중앙에서 처리해줄 수 있도록 해야함. while (true) { Receive(); } }
public void PushUnicastDataToClient(CruMessage msg, int clientNum) { if (msg == null) { throw new ArgumentNullException("parameter is null"); } lock (_clientList) { _clientList[clientNum].PushUnicastData(msg); } }
// 클라이언트로 보낼 메시지 큐 // 큐의 사이즈가 커질 수 있으니... 메시지 통신 사이즈를 늘려야하나? // 큐는... 리스트 같은거라 Enqueue랑 Dequeue 동기화 안해줘도 상관없지 않나? public void PushBroadcastData(CruMessage msg) { if (msg == null) { throw new ArgumentNullException("parameter is null"); } lock (_sendQueue) { _sendQueue.Enqueue(msg); } }
// 클라이언트로부터 온 메시지들을 저장하는 큐 public void PushReceiveData(CruMessage msg, int clientNum) { if (msg == null) { throw new ArgumentNullException("msgs is null"); } lock (_receiveQueue) { _receiveQueue.Enqueue(msg); } }
// 데이터 사이즈는 버퍼의 최종 사이즈보다 같거나 작다. 왜냐하면, 보낼 때, buffer사이즈보다 작은 사이즈를 보내기 때문! // 만약 데이터 사이즈와 버퍼 사이즈가 같다면... 그건 추가적으로 오는 데이터가 있을 수 있다는거니... 추가적인 작업이 있어야 함. public CruMessage[] ReceiveByteToMsgs(byte[] buffer, int receiveDatasize) { CruMessage[] result; CruMessage temp; int headsize; int transferdDataSize = 0; short dataCnt; short type; int idx = 0; // 데이터 수 확인 headsize = CruNetworkProtocol.Head.HEADSIZE_DATACOUNT; dataCnt = BitConverter.ToInt16(buffer, 0); result = new CruMessage[dataCnt]; idx += headsize; // 개별 데이터 확인 headsize = CruNetworkProtocol.Head.HEADSIZE_TYPE; for (int i = 0; i < dataCnt; ++i) { // type 확인 type = BitConverter.ToInt16(buffer, idx); idx += headsize; // data 확인 switch (type) { case (short)CruNetworkProtocol.MSG_TYPE.RESULT_PLAYERS_LOCATION: temp = ExtractMutableDatas(type, buffer, idx, receiveDatasize, out transferdDataSize); idx += transferdDataSize; transferdDataSize = 0; break; default: temp = ExtractDatas(type, buffer, idx, receiveDatasize); idx += CruNetworkProtocol.GetMessageTotalSIze(type); break; } result[i] = temp; } if (idx > receiveDatasize) { return(null); } return(result); }
// Single Item public void Enqueue(CruMessage item) { if (item == null) { throw new ArgumentNullException("item is null"); } if (Count == _capacity) { throw new IndexOutOfRangeException("queue is full"); } lock (_queue) { _queue.Enqueue(item); } }
public int ConnectToGame(string id, string token) { /* 순서 */ /* 먼저 아이디와 토큰정보를 받아서 유저 체크를 한다. * 제대로 인증되면, 그 때, ClientData를 통해 주기적으로 통신(Thread 실행)을 받는다. */ byte[] buffer = new byte[1024]; int result = 0; int datasize = 0; CruMessage msg = new CruMessage(CruNetworkProtocol.MSG_TYPE.CHECK_USER, new object[2] { id, token }); datasize = _messageTransfer.ExtractSendDatas(msg, buffer, 0); // 로그인 서버 포트로 연결할 것 Socket client = Connect("localhost", 0); // 로그인 정보 전달. client.Send(buffer, 0, datasize, SocketFlags.None); Array.Clear(buffer, 0, buffer.Length); datasize = client.Receive(buffer, 0, buffer.Length, SocketFlags.None); msg = _messageTransfer.ExtractDatas(CruNetworkProtocol.MSG_TYPE.CHECK_USER, buffer, 0, datasize); // datas = _messageTransfer. result = (int)msg.Datas[0]; // 제대로 연결되었다면 if (result == 1) { // 제대로 연결되었기에 ClientData 할당. 아닌가...? 그냥 새로 하나 만들까? _client = new ClientData(client, (int)msg.Datas[1]); // 제대로 사용하려면, 미리 Event를 할당해놓아야 한다. _client.sendCompleteCommonEvent = ProcessSend; _client.receiveCompleteCommonEvent = ProcessReceive; _client.StartDataTransmit(); } else { // 제대로 연결이 되지 않았을 때 처리. } return(result); }
public void Push(CruMessage item) { if (item == null) { throw new ArgumentNullException("item is null"); } if (Count == _capacity) { throw new IndexOutOfRangeException("pool is full"); } item.Initialize(0, null); lock (_pool) { _pool.Push(item); } }
// 연결되었다면 token값 할당. 아니라면 token == null public int ConnectToLogin(string id, string pw, out string token) { // todo // id, pw를 로그인서버로 검증받아서 token을 받는다. // 결과로 온 연결 실패 값에 따라 다른 명령 처리할 것. byte[] buffer = new byte[1024]; int datasize = 0; int result = 0; token = null; CruMessage msg = new CruMessage(CruNetworkProtocol.MSG_TYPE.LOGIN_REQUEST, new object[2] { (string)id, (string)pw }); // 로그인 요청할 데이터 세팅 datasize = _messageTransfer.SingleMsgToSendData(msg, buffer, 0, buffer.Length); //byte[] buffer = _messageTransfer.DatasToByte(CruNetworkProtocol.MSG_TYPE.LOGIN_REQUEST, datas); // 로그인 서버 포트로 연결할 것 Socket client = Connect("localhost", 8080); if (client == null) { return(-1); } // 로그인 정보 전달. client.Send(buffer, 0, datasize, SocketFlags.None); Array.Clear(buffer, 0, buffer.Length); datasize = client.Receive(buffer, 0, buffer.Length, SocketFlags.None); CruMessage[] receivemsg = _messageTransfer.ReceiveByteToMsgs(buffer, datasize); result = (short)receivemsg[0].Datas[0]; if (result == 0) { token = (string)receivemsg[0].Datas[1]; } return(result); }
// 메시지들을 클라이언트로 보낼 byte[]로 변환. public int SingleMsgToSendData(CruMessage msg, byte[] buffer, int offset, int buffersize) { byte[] temp; int datasize = 0; int msgSize = 0; int dataCnt = 1; // 보낼 데이터 수 //datasize = CruNetworkProtocol.Head.HEADSIZE_DATACOUNT; temp = BitConverter.GetBytes((short)dataCnt); Array.Copy(temp, 0, buffer, offset, temp.Length); datasize += temp.Length; // 데이터 처리 { // msg 추출 switch (msg.Type) { case (short)CruNetworkProtocol.MSG_TYPE.RESULT_PLAYERS_LOCATION: msgSize = ExtractMutableSendDatas(msg, buffer, datasize); break; default: msgSize = ExtractSendDatas(msg, buffer, datasize); break; } if (msgSize == 0) { throw new SystemException("메시지를 변환하는 과정에서 오류가 발생했습니다."); } // 추출된 byte 수 만큼 datasize 증가. datasize += msgSize; } if (datasize > buffersize) { throw new SystemException("buffer size를 초과하였습니다."); } return(datasize); }
// CruMessage를 만드는 곳 public CruMessage ExtractDatas(short type, byte[] buffer, int offset, int totalmsgssize) { CruMessage result; object[] datas; int[] datasizelist; CruNetworkProtocol.DATA_TYPE[] typelist; int bufferIdx = 0; int setDataSize = 0; datasizelist = CruNetworkProtocol.GetMessageSizeList(type); typelist = CruNetworkProtocol.GetMessageTypeList(type); datas = new object[datasizelist.Length - 1]; for (int i = 1; i < datasizelist.Length; ++i) { // 실제 버퍼 입력받을 위치 bufferIdx = offset + setDataSize; // 다음에 처리할 사이즈가 총 버퍼의 사이즈를 넘어간다면, if (bufferIdx + datasizelist[i] > totalmsgssize) { throw new SystemException("버퍼 사이즈를 넘겼습니다."); } // 데이터 Get switch (typelist[i]) { case CruNetworkProtocol.DATA_TYPE.BOOLEAN: datas[i - 1] = BitConverter.ToBoolean(buffer, bufferIdx); break; case CruNetworkProtocol.DATA_TYPE.SHORT: datas[i - 1] = BitConverter.ToInt16(buffer, bufferIdx); break; case CruNetworkProtocol.DATA_TYPE.INT: datas[i - 1] = BitConverter.ToInt32(buffer, bufferIdx); break; case CruNetworkProtocol.DATA_TYPE.FLOAT: datas[i - 1] = BitConverter.ToSingle(buffer, bufferIdx); break; case CruNetworkProtocol.DATA_TYPE.DOUBLE: datas[i - 1] = BitConverter.ToDouble(buffer, bufferIdx); break; case CruNetworkProtocol.DATA_TYPE.STRING: { int stringsize = BitConverter.ToInt16(buffer, bufferIdx); datas[i - 1] = Encoding.ASCII.GetString(buffer, bufferIdx + CruNetworkProtocol.Head.HEADSIZE_STRING, stringsize); } break; default: break; } setDataSize += datasizelist[i]; } // 변화한 데이터 사이즈가, 총량을 넘어갔을 때 ㅇㅇ if (setDataSize > datasizelist[0]) { return(null); } result = new CruMessage(type, datas); return(result); }
public int ExtractMutableSendDatas(CruMessage msg, byte[] buffer, int offset) { /* * 일반적으로 가변데이터 형식은 똑같다. * type + data갯수 + (data 정보들) + (data 정보들) + ... */ byte[] temp; short type = msg.Type; object[] datas = msg.Datas; int headSize = 0; int dataCnt = datas.Length; int dataSize = 0; int totalDataSize = 0; int[] datasizelist; CruNetworkProtocol.DATA_TYPE[] typelist; headSize = CruNetworkProtocol.Head.HEADSIZE_TYPE; datasizelist = CruNetworkProtocol.GetMessageSizeList(type); typelist = CruNetworkProtocol.GetMessageTypeList(type); // type 처리 temp = BitConverter.GetBytes(type); Array.Copy(temp, 0, buffer, offset + dataSize, headSize); dataSize += headSize; // data count 처리 temp = BitConverter.GetBytes((short)datas[0]); Array.Copy(temp, 0, buffer, offset + dataSize, datasizelist[1]); dataSize += datasizelist[1]; // data 처리 for (int i = 1; i < dataCnt; ++i) { for (int j = 2; j < datasizelist.Length; ++j) { // 버퍼 사이즈 넘어가는지 체크 if (offset + dataSize + datasizelist[j] > buffer.Length) { throw new SystemException("버퍼 사이즈를 넘어갑니다."); } switch (typelist[j]) { case CruNetworkProtocol.DATA_TYPE.BOOLEAN: temp = BitConverter.GetBytes((bool)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.SHORT: temp = BitConverter.GetBytes((short)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.INT: temp = BitConverter.GetBytes((int)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.FLOAT: temp = BitConverter.GetBytes((float)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.DOUBLE: temp = BitConverter.GetBytes((double)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.STRING: { short stringsize; temp = new byte[datasizelist[j]]; if ((string)datas[i] == null) { stringsize = 0; } else { stringsize = (short)((string)datas[i]).Length; } // Set string size Array.Copy(BitConverter.GetBytes(stringsize), temp, CruNetworkProtocol.Head.HEADSIZE_STRING); // Set string data if (datas[i] != null) { Encoding.ASCII.GetBytes((string)datas[i], 0, ((string)datas[i]).Length, temp, CruNetworkProtocol.Head.HEADSIZE_STRING); } } break; default: break; } Array.Copy(temp, 0, buffer, offset + dataSize, datasizelist[j]); dataSize += datasizelist[j]; } } // 총 데이터 사이즈 = 헤드사이즈 + 데이터묶음 수 사이즈 + ((데이터 묶음 사이즈) * 데이터 묶음 수) totalDataSize = headSize + datasizelist[1] + ((datasizelist[0] - datasizelist[1]) * (short)datas[0]); if (dataSize != totalDataSize) { return(0); } return(dataSize); }
public int ExtractSendDatas(CruMessage msg, byte[] buffer, int offset) { byte[] temp; short type = msg.Type; object[] datas = msg.Datas; int headSize = 0; int dataSize = 0; int[] datasizelist; CruNetworkProtocol.DATA_TYPE[] typelist; headSize = CruNetworkProtocol.Head.HEADSIZE_TYPE; datasizelist = CruNetworkProtocol.GetMessageSizeList(type); typelist = CruNetworkProtocol.GetMessageTypeList(type); temp = BitConverter.GetBytes(type); Array.Copy(temp, 0, buffer, offset + dataSize, headSize); dataSize += headSize; for (int i = 0; i < msg.Datas.Length; ++i) { // 버퍼 사이즈 넘어가는지 체크 if (offset + dataSize + datasizelist[i + 1] > buffer.Length) { throw new SystemException("버퍼 사이즈를 넘어갑니다."); } switch (typelist[i + 1]) { case CruNetworkProtocol.DATA_TYPE.BOOLEAN: temp = BitConverter.GetBytes((bool)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.SHORT: temp = BitConverter.GetBytes((short)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.INT: temp = BitConverter.GetBytes((int)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.FLOAT: temp = BitConverter.GetBytes((float)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.DOUBLE: temp = BitConverter.GetBytes((double)datas[i]); break; case CruNetworkProtocol.DATA_TYPE.STRING: { short stringsize; temp = new byte[datasizelist[i + 1]]; if ((string)datas[i] == null) { stringsize = 0; } else { stringsize = (short)((string)datas[i]).Length; } // Set string size Array.Copy(BitConverter.GetBytes(stringsize), temp, CruNetworkProtocol.Head.HEADSIZE_STRING); // Set string data if (datas[i] != null) { Encoding.ASCII.GetBytes((string)datas[i], 0, ((string)datas[i]).Length, temp, CruNetworkProtocol.Head.HEADSIZE_STRING); } } break; default: break; } Array.Copy(temp, 0, buffer, offset + dataSize, datasizelist[i + 1]); dataSize += datasizelist[i + 1]; } if (dataSize != datasizelist[0] + headSize) { return(0); } return(dataSize); }
public void PushMessage(CruMessage msg) { _client.PushUnicastData(msg); }
// bool 형으로 만들어서 제대로 처리되었는지 확인해야할까...? public void MessageHandle(CruMessage msg, int clientNum) { CruNetworkProtocol.MSG_TYPE type = (CruNetworkProtocol.MSG_TYPE)msg.Type; switch (type) { case CruNetworkProtocol.MSG_TYPE.LOGIN_REQUEST: onLoginRequestEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.LOGIN_ACK: onLoginACKEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.CHECK_USER: onCheckUserEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.CHECK_USER_ACK: onCheckUserACKEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.PLAYER_DATA: onPlayerDataEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.CUSTOM_PLAYER_DATA: onCustomPlayerDataEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.PLAYER_LOCATION: onPlayerLocation(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.ITEM_DATA: onItemDataEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.MOVE: onMoveEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.LOOK: onLookEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.ITEM_BUY: onItemBuyEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.REQUEST_PLAYERS_LOCATION: onRequestPlayersLocation(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.RESULT_GETEXP: onResultGetEXPEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.RESULT_LEVELUP: onResultLevelUpEvent(msg, clientNum); break; case CruNetworkProtocol.MSG_TYPE.RESULT_ATTACK: onResultAttackEvent(msg, clientNum); break; default: throw new SystemException("해당 명령이 존재하지 않습니다."); } }