Esempio n. 1
0
        // 콜백 함수
        void AcceptCallback(IAsyncResult ar)
        {// 클라이언트의 접속 요청이 Accept 되었을 때 호출되는 콜백함수
            // 클라이언트의 연결 요청을 수락한다.
            Socket client = server_socket.EndAccept(ar);

            // 또 다른 클라이언트의 연결을 대기한다.
            server_socket.BeginAccept(AcceptCallback, null);

            // 비동기 통신을 위한 AsyncObject 객체 생성 및 소켓 지정
            AsyncObject obj = new AsyncObject(4096);

            obj.WorkingSocket = client;

            // 클라이언트의 닉네임을 얻는다.
            GetNickname(client);

            // 연결된 클라이언트 딕셔너리에 추가해준다.
            connected_clients.Add(client_nickname, client);

            // 클라이언트에게 플레이어 번호를 할당해준다.
            SendPlayerNum();

            // 현재 접속한 플레이어 수에 따라 이미지를 동기화 해준다.
            switch (player_count)
            {
            case 2:
                pb_human2.Image = img_pHuman.Images[0];
                break;

            case 3:
                pb_human2.Image = img_pHuman.Images[0];
                pb_human3.Image = img_pHuman.Images[0];
                break;

            case 4:
                pb_human2.Image = img_pHuman.Images[0];
                pb_human3.Image = img_pHuman.Images[0];
                pb_human4.Image = img_pHuman.Images[0];
                break;
            }

            // 모든 클라이언트에게 마지막 클라이언트가 연결되었다고 써준다.
            // 문자열을 utf8 형식의 바이트로 변환한다.
            // 현재 접속한 플레이어 수와 클라이언트 연결 메세지를 보낸다.
            string tts = string.Format("<System>{0}({1}P)님이 입장하였습니다.", client_nickname, player_count);

            byte[] bDts = Encoding.UTF8.GetBytes(player_count.ToString() + '\x01' + tts);

            // 연결된 모든 클라이언트에게 전송한다.
            //for(int i = connected_clients.Count - 1; i >= 0; i--)
            foreach (string nickname in connected_clients.Keys)
            {
                Socket socket = connected_clients[nickname];
                try
                {
                    socket.Send(bDts);
                }
                catch
                {
                    // 오류 발생하면 전송 취소하고 리스트에서 삭제한다.
                    try
                    {
                        socket.Dispose();
                    }
                    catch
                    {
                    }
                    connected_clients.Remove(nickname);
                }
            }

            // 전송 완료 후 텍스트 박스에 추가한다.
            AppendText(rtb_chat, string.Format("<System>{0}({1}P)님이 입장하였습니다.", client_nickname, player_count));

            // 클라이언트의 데이터를 받는다.
            client.BeginReceive(obj.Buffer, 0, 4096, 0, DataReceived, obj);
        }
Esempio n. 2
0
        void DataReceived(IAsyncResult ar)
        {// 데이터 받기 - 서버, 클라이언트 둘 다 사용
            // BeginReceive에서 추가적으로 넘어온 데이터를 Asyncobject 형식으로 변환한다.
            AsyncObject obj = (AsyncObject)ar.AsyncState;

            // 데이터 수신을 끝낸다.
            int received = obj.WorkingSocket.EndReceive(ar); // 클라 끄면 서버 꺼지는 이유

            // 받은 데이터가 없으면(연결 끊어짐) 끝낸다.
            if (received <= 0)
            {
                obj.WorkingSocket.Close();
                return;
            }

            // 텍스트로 변환한다.
            string text = Encoding.UTF8.GetString(obj.Buffer);

            // 0x01 기준으로 자른다. == '\x01' 기준으로 자른다.
            // tokens[0] - 보낸 사람 닉네임
            // tokens[1] - 보낸 메세지
            // tokens[2] - 보낸 사람 플레이어 번호
            string[] tokens = text.Split('\x01');
            if (tokens.Length == 3)  // 토큰이 셋이면 채팅 메세지이다.
            {
                string nickname   = tokens[0];
                string msg        = tokens[1];
                string player_num = tokens[2].Trim('\0');

                // 텍스트 박스에 추가해준다.
                // (비동기식으로 작업하기 때문에 폼이 UI 스레드에서 작업을 해줘야 한다.
                // 따라서 대리자를 통해 처리한다.(Invoke))
                AppendText(rtb_chat, string.Format("({0}P){1}: {2}", player_num, nickname, msg));
            }
            else if (tokens.Length == 2) // 토큰이 둘이면 <System> 메세지이다.
            {
                current_player_num = Int32.Parse(tokens[0]);
                string system_msg = tokens[1].Trim('\0');
                // 텍스트 박스에 추가해준다.
                // (비동기식으로 작업하기 때문에 폼이 UI 스레드에서 작업을 해줘야 한다.
                // 따라서 대리자를 통해 처리한다.(Invoke))
                AppendText(rtb_chat, system_msg);
            }

            if (is_server)  // 함수를 호출한 프로세스가 서버이면
            {
                // 모든 클라이언트에게 전송
                foreach (string nickname in connected_clients.Keys)
                {
                    Socket socket = connected_clients[nickname];
                    if (socket != obj.WorkingSocket)
                    {
                        try
                        {
                            socket.Send(obj.Buffer);
                        }
                        catch
                        {
                            // 오류 발생하면 전송 취소하고 리스트에서 삭제한다.
                            try
                            {
                                socket.Dispose();
                            }
                            catch
                            {
                            }
                            connected_clients.Remove(nickname);
                        }
                    }
                }

                // 데이터를 받은 후엔 다시 버퍼를 비워주고
                obj.ClearBuffer();

                // 같은 방법으로 수신을 대기한다.
                obj.WorkingSocket.BeginReceive(obj.Buffer, 0, 4096, 0, DataReceived, obj);
            }
            else // 함수를 호출한 프로세스가 클라이언트이면
            {
                // 플레이어의 접속 이미지를 동기화 한다.
                switch (current_player_num)
                {
                case 2:
                    pb_chat.Image   = img_pNumber.Images[1];
                    pb_human1.Image = img_pHuman.Images[0];
                    pb_human2.Image = img_pHuman.Images[0];
                    break;

                case 3:
                    pb_chat.Image   = img_pNumber.Images[2];
                    pb_human1.Image = img_pHuman.Images[0];
                    pb_human2.Image = img_pHuman.Images[0];
                    pb_human3.Image = img_pHuman.Images[0];
                    break;

                case 4:
                    pb_chat.Image   = img_pNumber.Images[3];
                    pb_human1.Image = img_pHuman.Images[0];
                    pb_human2.Image = img_pHuman.Images[0];
                    pb_human3.Image = img_pHuman.Images[0];
                    pb_human4.Image = img_pHuman.Images[0];
                    break;
                }

                // 클라이언트에선 데이터를 전달해줄 필요가 없으므로 바로 수신 대기한다.
                // 데이터를 받은 후엔 다시 버퍼를 비워주고
                obj.ClearBuffer();

                // 같은 방법으로 수신을 대기한다.
                obj.WorkingSocket.BeginReceive(obj.Buffer, 0, 4096, 0, DataReceived, obj);
            }
        }
Esempio n. 3
0
        private void btn_Client_Click(object sender, EventArgs e)
        {
            if (client_socket.Connected)
            {
                MsgBoxHelper.Error("이미 연결되어 있습니다!");
                return;
            }

            int port;

            if (!int.TryParse(txt_port.Text, out port))
            {
                lbl_loginAlert.ForeColor = Color.Red;
                lbl_loginAlert.Text      = "잘못된 포트번호입니다.";
                txt_port.Focus();
                txt_port.SelectAll();
                return;
            }
            if (txt_nickname.Text == "")
            {
                lbl_loginAlert.ForeColor = Color.Red;
                lbl_loginAlert.Text      = "잘못된 닉네임입니다.";
                txt_nickname.Focus();
                txt_nickname.SelectAll();
                return;
            }

            changePhase(PHASE.CONNECTING);

            try
            {
                client_socket.Connect(txt_ip.Text, port);
            }
            catch (Exception ex)
            {
                lbl_loginAlert.ForeColor = Color.Red;
                lbl_loginAlert.Text      = "연결에 실패했습니다!";
                changePhase(PHASE.LOGIN);
                return;
            }

            // 연결 완료되었다는 메세지를 띄워준다.
            //AppendText(rtb_chat, "서버와 연결되었습니다.");

            // 클라이언트 자신의 닉네임을 설정한다.
            my_nickname = txt_nickname.Text;

            // 서버에게 닉네임을 보낸다.
            SendNickname();

            // 서버에게서 플레이어 번호를 할당받는다.
            GetPlayerNum();

            //게임인터페이스로 이동
            changePhase(PHASE.LOBBY);    // 로비로 이동.(준비 전 상태)

            // 채팅창을 사용 가능하도록 변경
            txt_send.Enabled  = true;
            btn_send.Enabled  = true;
            btn_ready.Enabled = true;

            // 연결 완료, 서버에서 데이터가 올 수 있으므로 수신 대기한다.
            AsyncObject obj = new AsyncObject(4096);

            // 데이터 송신을 대기할 소켓 지정
            obj.WorkingSocket = client_socket;
            // 해당 소켓이 비동기로 데이터를 받는 함수 BeginReceive 호출
            client_socket.BeginReceive(obj.Buffer, 0, obj.BufferSize, 0, DataReceived, obj);
        }