Microsoft MVP성태의 닷넷 이야기
안녕하세요 질문하나만드리겠습니다...! [링크 복사], [링크+제목 복사]
조회: 3991
글쓴 사람
김경한 (hwan4170 at naver.com)
홈페이지
첨부 파일
 

amespace MultiChatServer {
    public partial class ChatForm : Form {
        delegate void AppendTextDelegate(Control ctrl, string s);
        AppendTextDelegate _textAppender;
        Socket mainSock;
        IPAddress thisAddress;

        public ChatForm() {
            InitializeComponent();
            mainSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            _textAppender = new AppendTextDelegate(AppendText);
            DataTable table = new DataTable();
            table.Columns.Add("");
            table.Columns.Add("Number", typeof(int));
            table.Columns.Add("Data", typeof(float));
            table.Columns.Add("");
            table.Rows.Add("", "1", "99.5", "");
            table.Rows.Add("", "2", "24.2", "");
            table.Rows.Add("", "3", "53.2", "");

            dataGridView1.DataSource = table;
        }//선언
        
        void AppendText(Control ctrl, string s) {
            if (ctrl.InvokeRequired) ctrl.Invoke(_textAppender, ctrl, s);
            else {
                string source = ctrl.Text;
                ctrl.Text = source + Environment.NewLine + s;
            }
        }

        void OnFormLoaded(object sender, EventArgs e) {
            IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());

       
            foreach (IPAddress addr in he.AddressList) {
                if (addr.AddressFamily == AddressFamily.InterNetwork) {
                    thisAddress = addr;
                    break;
                }
            }

          
            if (thisAddress == null)
      
                thisAddress = IPAddress.Loopback;

            txtAddress.Text = thisAddress.ToString();
        }
        void BeginStartServer(object sender, EventArgs e) {
            int port;
            if (!int.TryParse(txtPort.Text, out port)) {
                MsgBoxHelper.Error("포트 번호가 잘못 입력되었거나 입력되지 않았습니다.");
                txtPort.Focus();
                txtPort.SelectAll();
                return;
            }

            IPEndPoint serverEP = new IPEndPoint(thisAddress, port);
            mainSock.Bind(serverEP);
            mainSock.Listen(10);

            
            mainSock.BeginAccept(AcceptCallback, null);
        }

        List<Socket> connectedClients = new List<Socket>();
        void AcceptCallback(IAsyncResult ar) {
           
            Socket client = mainSock.EndAccept(ar);

           
            mainSock.BeginAccept(AcceptCallback, null);

            AsyncObject obj = new AsyncObject(4096);
            obj.WorkingSocket = client;

          
            connectedClients.Add(client);
            
            AppendText(txtHistory, string.Format("사용자 (@ {0})가 연결되었습니다.", client.RemoteEndPoint));

            
            client.BeginReceive(obj.Buffer, 0, 4096, 0, DataReceived, obj);
        }

        void DataReceived(IAsyncResult ar) {
            AsyncObject obj = (AsyncObject)ar.AsyncState;

           
            //예외처리 구문 (튕김방지)
            string text = Encoding.UTF8.GetString(obj.Buffer);

            
            string[] tokens = text.Split(' ');
            string ip = tokens[0];
            string msg = tokens[0];

           
            AppendText(txtHistory, string.Format("[받음]{0}: {1}", ip, msg));
            
            
            for (int i = connectedClients.Count - 1; i >= 0; i--) {
                Socket socket = connectedClients[i];
                if (socket != obj.WorkingSocket) {
                    try { socket.Send(obj.Buffer); }
                    catch {
                       
                        try { socket.Dispose(); } catch { }
                        connectedClients.RemoveAt(i);
                    }
                }
            }

            try
            {
                int received = obj.WorkingSocket.EndReceive(ar);
            }
            catch (Exception e)
            {
                string Message = "서버가 끊어졌습니다" + e.Message;
                MessageBox.Show(Message);
                return;
            }


            obj.ClearBuffer();

         
            obj.WorkingSocket.BeginReceive(obj.Buffer, 0, 4096, 0, DataReceived, obj);
        }

        void OnSendData(object sender, EventArgs e) {
            
            if (!mainSock.IsBound) {
                MsgBoxHelper.Warn("서버오프라인 상태");
                return;
            }
            
            
            string tts = txtTTS.Text.Trim();
            if (string.IsNullOrEmpty(tts)) {
                MsgBoxHelper.Warn("텍스트가 입력되지 않았습니다!");
                txtTTS.Focus();
                return;
            }
            
           
            byte[] bDts = Encoding.UTF8.GetBytes(thisAddress.ToString() + '\x01' + tts);

           
            for (int i = connectedClients.Count - 1; i >= 0; i--) {
                Socket socket = connectedClients[i];
                try { socket.Send(bDts); } catch {
                   
                    try { socket.Dispose(); } catch { }
                    connectedClients.RemoveAt(i);
                }
            }

            
            AppendText(txtHistory, string.Format("[보냄]{0}: {1}", thisAddress.ToString(), tts));
            txtTTS.Clear();
        }

        private void lblPort_Click(object sender, EventArgs e)
        {

        }

        private void txtHistory_TextChanged(object sender, EventArgs e)
        {

        }

        private void lblAddress_Click(object sender, EventArgs e)
        {

        }

        private void tblMainLayout_Paint(object sender, PaintEventArgs e)
        {

        }

현재 제가 c#으로 tcp/ip 송수신프로그램을 만들어서 짜놓고 실행까지 구현을 해놓은 코드입니다.
다름이아니라 여기서좀더 나아가 옆에 데이타그리드를 통해 표를만들어
클라이언트 쪽에서 예를들어 [ 1, 99.9% ]
이런식으로 텍스트를 전송하게되면 조건문으로 걸어서 그리드쪽으로자동기입이되도록하고싶은데요..
어느부분에서 어떤함수를대략적으로 추가해야 그리드쪽으로 넘어가는지를 도통모르겠습니다..
조건문은 하다보면 될거같은데 넘어가도록 하는 코드를 어디에무엇을추가해야하는지모르겠어요...








[최초 등록일: ]
[최종 수정일: 9/6/2022]


비밀번호

댓글 작성자
 



2022-09-07 12시45분
이런 경우에는, 너무 조급하게 생각하지 마시고 코드를 하나씩 분리해서 실습해 보세요.

소켓 통신 코드 없이, 단순히 그리드만 올려 놓은 코드를 작성한 후 그것에 어떻게 항목을 삽입할 수 있는지 문서를 보시면 됩니다.

DataGrid Class
; https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.datagrid

그것 먼저 해보시고, 이후 소켓으로부터 전달받은 텍스트를 그리드에 추가하는 코드와 연동하면 됩니다. 분명히, 하실 수 있으니 ^^ 시도해 보세요. 그래도 안 되시면 그때까지의 소스 코드를 다시 올려주세요.
정성태
2022-09-07 02시16분
[김경한] 먼저 댓글에 감사드립니다 말씀하신대로 그리드만 먼저 공부를 진행하였는데 댓글에 달아주신 링크를
보아도 도통감이 잡히지를않습니다.. 도와주실수있을까요..
[guest]
2022-09-07 02시29분
아래의 글을 따라해 보세요.

C# DataGridView에 데이터 넣기 예제
; https://kinghell.tistory.com/57

그런 다음, 구체적으로 어느 부분을 모르겠는지 소스 코드와 함께 다시 질문해 주세요.
정성태
2022-09-07 02시41분
[김경한] 답변에감사드립니다 방금 링크해주신 데이터넣기예제도 구글링하다 찾아서 직접 실행까지해봤습니다 이예제는 무리없이 할수있지만

제가 위에 작성해논 tcp/ip 프로그램에서는 클라이언트측에서 서버측으로 대화를 보낼때 클라이언트쪽에서 [ number, data, ] 이런식으로하여금
보내주면 서버측에서는 별도의 저장없이 그리드표쪽으로 바로 조건물을 [ 이런식을 시작될떄 저장같은것으로 걸어서 그리드에저장되게하려고하는데요.
예제는 제가 데이터를 그리드자체에 넣는것이고 통수신에서 서버쪽에서조건문걸어서저장되게해야하는데 이부분이 어딜건드려야할지 감이전혀오질않습니다선생님
[guest]
2022-09-07 03시24분
정리해 보면, 클라이언트에서 (예를 들어) "[50, 99.9%]"라는 문자열로 보내오는데, 그렇게 "[" 대괄호로 시작하는 문자열이 오는 경우에는 서버에서 DataGrid로 보여주고 싶다는 거죠?

근데... 이미 프로그래밍을 대충 잘 하셨습니다. 작성하신 코드에 보면 AppendText 메서드가 사실상 들어온 문자열을 처리하고 있는 듯한데요, 단지 그것은 TextBox에 데이터를 넣는 것이니, 그 메서드에서만 DataGrid로 넣는 코드를 추가해 주시면 됩니다.

가령, DataGrid로 넣는 메서드를 AddTextToDataGrid로 만들었다고 했을 때 AppendText에는 이렇게만 추가하면 됩니다.

if (source[0] == '[')
{
    AddTextToDataGrid(source);
}

이해가 될 때까지 설명해 드릴 테니, 계속 모르는 사항들을 질문해 주세요.
정성태
2022-09-07 04시33분
[김경한] public ChatForm() {
            InitializeComponent();
            mainSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            _textAppender = new AppendTextDelegate(AppendText);
            DataTable table = new DataTable();
            table.Columns.Add("");
            table.Columns.Add("Number", typeof(int));
            table.Columns.Add("Data", typeof(float));
            table.Columns.Add("");
       

            dataGridView1.DataSource = table;
        }//선언
        
        void AppendText(Control ctrl, string s) {
            if (ctrl.InvokeRequired) ctrl.Invoke(_textAppender, ctrl, s);
            else {
                string source = ctrl.Text;
                ctrl.Text = source + Environment.NewLine + s;
            }
            if (source[0] == '[')
            {
                AddTextToDataTable(source);
            }


        }
항상감사드립니다
소스코드를보면 DataGrid로 넣는 메서드가 ... table로 잡아야하는거 같기도한데
만약테이블로잡고 저렇게 넣엇다고하면 if 문을 어디에넣어야하는지잘모르겠습니다..
연동시키는부분잡는게 너무어렵네요저한테는.. ㅜㅜ
[guest]
2022-09-07 06시08분
위와 같은 경우에는 if 문을 그 위에 ctrl.InvokeRequired의 else 절 내부에 넣는 것이 맞습니다.

void AppendText(Control ctrl, string s) {
    if (ctrl.InvokeRequired) ctrl.Invoke(_textAppender, ctrl, s);
    else {
        string source = ctrl.Text;
        ctrl.Text = source + Environment.NewLine + s;

        if (source[0] == '[')
        {
            AddTextToDataTable(source);
        }
    }
}
정성태
2022-09-08 09시10분
[김경한] 감사합니다 선생님말씀대로 위치는 잡았는데 서버와 클라이언트 접속을시키니까
if (source[0] == '[')
                {
                    AddTextToDataTable(source);
                }
            }

        }

'[' 쪽에서 인덱스배열범위를벗어난오류와
AddTextToDataTable(source);이 이름이현재컨텍스트에없다고 나오는데 위에선언을햇는데도 불구하고 이런오류가나오네요.....
[guest]
2022-09-08 09시22분
그 문제는, 해당 오류 메시지를 의미있게 해석해 보시면 분명히 이해할 수 있으니 스스로 해결하실 것을 권합니다. 현재 김경한 님의 상황을 봐서는 앞으로도 계속해서 오류가 발생할 텐데 그때마다 매번 질문으로 해결하면서 프로젝트를 진행할 수는 없습니다.

참고로, 아래의 영상은 자신의 소스 코드에서 왜 그런 동작을 하는지 비주얼 스튜디오를 이용해 진단하는데 도움을 줄 것입니다.

비주얼 스튜디오 디버그 기능 기초 활용
; https://www.youtube.com/watch?v=X3_OXIIDEec
정성태
2022-09-08 09시48분
[김경한] 알겠습니다 선생님 조언해주신대로 좀더 심도있게 고민하고 공부해보겟습니다.!
[guest]

1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
5829수박942/19/20233419키움 API를 윈폼과 WPF의 네임스페이스 없이 콘솔이나 WinUI3에서 사용할 수 있는 방법이 있나요? [2]파일 다운로드1
5828김재영2/19/20233202장기적으로는 this 구문을 안쓰는게 맞을까요? [2]
5827lee2/18/20233127파이썬 설치 오류 질문입니다 [1]
5826Syong2/14/20233692Socket 관련 Leak (OverlappedAsyncResult, OverlappedData) 관련 문의 [7]파일 다운로드1
5825박성원2/14/20233256Listview 컨트롤의 화면 전환 시 갱신 속도 [1]
5823검은콩2/13/20233849catch(Exception ex)의 line번호를 쉽게 알 수 없는지요? [7]
5822김지우2/11/20233123책을 보면서 sync, async 이해가 되지 않는 부분이 있습니다. [5]파일 다운로드2
5821검은콩2/9/20233139Async 신뢰성과 소켓데이터 [4]
5820차가워2/8/20233216다른 프로세스 실행 후 포커스 가져오기 [3]
5819취준생2/7/20233361WPF 관련 실무가 궁금합니다. [3]
5818윤길2/7/20232805ObservableCollection 에서 INotifyPropertyChanged 구현해야하나요? [2]
5817흰털너부리2/7/20232946배포 시 winform 실행 콘솔로그 보는 방법 [1]
5816흰털너부리2/6/20232760.net core json array validation 질문 드립니다. [1]
5815김재영2/6/20232882종단간 암호화에 대해 시나리오인데 타당한 시나리오일까요? [2]
5814한예지 donator2/6/20233225decompile? [9]
5813김재영2/5/20233102openssl genrsa 2048시 키 생성이 다르게 됩니다. - 파일첨부 [4]파일 다운로드1
5812김재영2/5/20233380openssl genrsa 2048시 키 생성이 다르게 됩니다. [2]
5811치르바2/3/20233210MiniDumpWriteDump API로 덤프수집을 했는데요.. [3]
5810이건우1/31/20233327윈도우서비스를 통한 웹통신관련 질문입니다 [3]
5809이상훈1/31/20233755다채널 영상 디스플레이어 개발 관련 질문입니다. [3]
5808근우1/30/20233434WPF 에서 UserControl 과 ControlTemplate 의 차이점은 무엇인가요? [6]
5807궁금맨1/28/20234590C# 10 책에 나온 예제의 결과가 제 컴에서는 좀 달라서요. 이유가 궁금합니다. [1]
5806스레드1/25/20233114총정리 - 다양한 스레드들 [초안] [1]파일 다운로드1
5805어웨이트1/25/20232979Taskcontinuewith vs Async/Await [2]파일 다운로드1
5804나이많은...1/25/20232841MS의 Dependency Injection(DI)에 AddSingleton으로 등록된 객체의 Event 등록후 사용시 앱 종료시 별도로 Event를 해지해야 하나요? [2]
5803dssc...1/24/20233064드라이브 문자를 통해서 물리 디스크 명칭을 알아내고 싶습니다. [1]
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...