[C# 윈폼] 윈폼 TCP/IP 통신 서버 프로그램 만들기

안녕하세요.

 

오늘은 C# 윈폼으로 TCP/IP 통신을 이용해서 서버/클라이언트 프로그램을 만들어서 클라이언트에서 서버로 메시지까지 보내는 프로그램을 만들려고 합니다.

 

우선 오늘은 그 첫 번째로, 서버(Server) 프로그램을 만들어 보려고 해요.

 

제가 만드는 예제 프로그램은, 서버는 내가 연결할 클라이언트의 IP를 미리 알고 있고, 해당 IP들을 가지고 있는 클라이언트에서 접속 연결을 하였을 때 연결을 해서 해당 클라이언트와 통신이 되는 프로그램을 만들려고 합니다.

 

그럼 바로 예제코드를 통해서 어떻게 서버 코드를 작성하는지 보여 드리도록 하겠습니다.

 

참고로, 저는 예제 프로그램은 MetroDesign을 이용해서 만들었지만, MetroDesign을 쓰지 않으셔도 되니까 이점은 참고만 해주시면 감사하겠습니다.

 

먼저 서버 프로그램 UI는 아래와 같이 구성하였습니다.

 

서버 프로그램 UI

 

위와 같이 서버 프로그램 UI 구성을 하였고, “클라이언트 접속 확인버튼을 누르면 서버가 가지고 있는 클라이언트의 IP 리스트들을 계속해서 확인하면서 해당 클라이언트의 접속이 오는지 체크하는 역할을 합니다.

 

그 외의 TextBox 컨트롤에서는 현재 접속된 클라이언트, 접속이 안된 클라이언트, 클라이언트로부터 받은 메시지를 나타내는 창 이렇게 3개의 TextBox 컨트롤을 배치하여 보여 주도록 UI 구성을 하였습니다.

 

그럼 해당 프로그램의 예제 코드를 작성해 보도록 하겠습니다.

 

예제 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Server
{
    public partial class Server : MetroFramework.Forms.MetroForm
    {
        ArrayList socklist = new ArrayList();
        public static string data = null;
        //클라이언트에게 오는 메시지를 받을 버퍼 선언
        private byte[] bytes = new byte[1024];
 
        public List<string> clientIP = new List<string>();
 
        public Server()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
        }
 
        public void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (socklist != null)
            {
                socklist = null;
            }
            Application.Exit();
        }
 
        public static string TruncateLeft(string value, int maxLength)
        {
            if (string.IsNullOrEmpty(value)) return value;
            return value.Length <= maxLength ? value : value.Substring(0, maxLength);
        }
 
        private void metroTile1_Click(object sender, EventArgs e)
        {
            SocketServer();
        }
 
 
        /// <summary>
        /// 클라에게 접속 연결 및 데이터 받는 함수
        /// </summary>
        public void SocketServer()
        {
            ClientIPStore();
 
            //클라이언트 IP를 알아서 해당 클라이언트에게 접속 요청
            new Thread(delegate ()
            {
                while (true)
                {
                    try
                    {
                        foreach (var client in clientIP)
                        {
                            // Create a TCP/IP Socket
                            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
                            // 클라이언트의 IP와 포트번호를 이용해 접속 시도
                            //sock.Connect(new IPEndPoint(IPAddress.Parse(client.ToString()), 12000));
                            IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(client.ToString()), 12000);
 
                            //각 클라이언트 Search 할 때 Timeout 걸어준다.
                            IAsyncResult result = sock.BeginConnect(IPAddress.Parse(client.ToString()), 12000nullnull);
                            bool success = result.AsyncWaitHandle.WaitOne(500true);
 
                            if (!success)
                            {
                                FailConnect(sock, client);
                            }
                            else
                            {
                                Invoke((MethodInvoker)delegate
                                {
                                    SuccessConnect(sock, client);
                                });
                            }
                        }
                    }
                    catch (SocketException se)
                    {
                        MessageBox.Show("해당 클라이언트가 없습니다.");
                    }
                    Invoke((MethodInvoker)delegate
                    {
                        tb_disconnect.AppendText(Environment.NewLine);
                        tb_connect.AppendText(Environment.NewLine);
                    });
                    Thread.Sleep(5000);
                }
            }).Start();
        }
 
        private void SuccessConnect(Socket sock, string client)
        {
            //lbConnect.Items.Add(client.ToString() + "[IP의 Client 연결 성공].");
            tb_connect.AppendText(client.ToString() + "[IP의 Client 연결 성공]." + Environment.NewLine);
            socklist.Clear();
            //현재 연결 되어있는 클라이언트들만 따로 ArrayList에 저장
            socklist.Add(sock);
            new Thread(delegate ()
            {
                while (true)
                {
                    try
                    {
                        data = null;
                        // Client에서 들어오는 연결을 처리한다.
                        while (true)
                        {
                            bytes = new byte[1024];
                            int bytesRec = sock.Receive(bytes);
                            data += Encoding.UTF8.GetString(bytes, 0, bytesRec);
                            Thread.Sleep(500);
                            if (data.IndexOf("<eof>"> -1)
                                break;
                        }
 
                        // Truncate the <eof>
                        data = TruncateLeft(data, data.Length - 5);
 
                        // Client에서 받은 메시지를 listbox로 보여줍니다.
                        Invoke((MethodInvoker)delegate
                        {
                            //lbRevMsg.Items.Add(string.Format("Text received : {0}", data));
                            tb_recv_msg.AppendText(string.Format(client.ToString() + "received : {0}", data) +
                                                   Environment.NewLine);
                        });
 
                        // 클라이언트에서 받은 메시지를 다시 클라이언트에게 에코해준다.
                        data = "[Server Echo 메시지]" + data;
                        byte[] msg = Encoding.UTF8.GetBytes(data);
 
                        //MessageBox.Show(data);
 
                        foreach (Socket socket in socklist)
                        {
                            socket.Send(msg);
                        }
                        //sock.Send(msg);
                    }
                    catch
                    {
                        //MessageBox.Show("Server : DISCONNECTION!");
                        sock.Close();
                        sock.Dispose();
                        break;
                    }
                }
            }).Start();
        }
 
        private void FailConnect(Socket sock, string client)
        {
            // NOTE, MUST CLOSE THE SOCKET
            sock.Close();
            Invoke((MethodInvoker)delegate
            {
                //lbDisconnect.Items.Add(client.ToString() + "[IP의 Client 연결 실패].");
                tb_disconnect.AppendText(client.ToString() + "[IP의 Client 연결 실패]." + Environment.NewLine);
            });
        }
 
        /// <summary>
        /// 서버가 관리하는 클라이언트들의 IP를 List를 이용하여 저장하고 있다.
        /// </summary>
        public void ClientIPStore()
        {
            clientIP.Add("10.10.30.103");
            clientIP.Add("210.218.130.190");
            clientIP.Add("192.168.0.4");
            clientIP.Add("10.10.30.102");
            clientIP.Add("10.10.30.104");
            clientIP.Add("10.10.30.105");
        }
    }
}
 
cs

 

실행 결과

 현재 서버쪽에서는 총 5개의 클라이언트 IP 정보 리스트를 가지고 있고, 아직은 해당 5개중에서 접속을 시도한 클라이언트가 없어서 접속 실패 클라이언트 쪽에 5개의 클라이언트 리스트의 내용이 출력되는 것을 보실 수 있습니다.

 

이 다음 포스팅에서는 클라이언트 프로그램을 만들어서 이제 서버와 접속 연결을 하고 클라이언트에서 서버쪽으로 메시지를 보내는 것 까지 구현해 보도록 하겠습니다.

 

감사합니다.^^

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY