ID 입력창입니다.
ID 입력 후 버튼 클릭 또는 키보드 엔터키 입력시 현재 창을 숨기고 클라이언트 폼을 띄웁니다.
클라이언트 폼입니다. 서버폼이랑 별 다를건 없습니다.
0. 전체 폼
FormClosing시 Disconnect() 메소드를 실행하게끔 합니다.
1. 채팅로그(RichTextBox, Name : ChatLog)
채팅 로그를 띄워줍니다. 서버 콘솔창과 마찬가지로 RichTextBox입니다.
2. 채팅 참가자 목록(ListBox, Name : ChatterList)
채팅 참가자 목록을 띄웁니다.
3. 대화 입력창(TextBox, Name : InputField)
일반 TextBox입니다. 키보드 엔터키 입력시 마찬가지로 전송되게끔 합니다.
이를 위해 KeyDown시 InputField_KeyDown() 메소드를 실행케 합니다.
4. 전송 버튼(Button, Name : EnterBtn)
클릭시 EnterBtn_Click() 메소드를 실행합니다.
5. 나가기 버튼(Button, Name : QuitBtn) // 나가는 명령어가 /exit라 ExitBtn으로 통일하는걸 깜빡했습니다..,
서버와 접속을 끊는 Disconnect() 메소드를 실행합니다.
ClientForm.cs 코드입니다.
Public CilentForm(string ID)
유저ID를 ID입력 폼에서 받아 폼을 생성합니다.
void Connect(string s)
InputField에서 /connect [클라이언트IP] [서버IP] [서버PORT] 입력시 서버와 연결합니다.
' '기준으로 문자열을 split해 IP를 얻어냅니다.
연결 실패시 메세지박스를 띄우며 적당히 예외처리를 추가하시면 되겠습니다.
void Display(string msg)
ChatLog에 메세지를 띄웁니다.
서버와 마찬가지로 CheckForIllegalCrossThreadCalls = false; 를 사용해 크로스 쓰레드 예외를 피합니다.
void Receiver()
서버로부터 오는 메세지를 받는 메소드입니다. 컨트롤 메세지일 경우 ChatLog에 띄우지 않고 따로 처리합니다.
bool isControlMsg(string msg)
컨트롤 메세지인 경우 그에 맞는 처리를 하고 ChatLog에 띄우지 않기 위해 bool형 변수를 반환합니다.
void Sender(string s)
서버로 메세지를 보내는 메소드입니다. 사실 Disconnect() 메소드의 전송부분도 Sender로 대체하면 되긴합니다. 새벽에 만드느라 살짝 엉성한 부분이 많네요
void Controller(string s)
InputField에서 메세지를 받아 컨트롤 메세지라면 맞는 처리를, 그렇지 않으면 서버에 그대로 전송합니다.
void Disconnet()
폼을 닫거나 나가기 버튼을 누를 때 서버와 연결을 끊습니다.
void InputField_Keydown(object sender, KeyEventargs e)
키보드의 엔터키 입력시 EnterBtn_Click()메소드를 실행합니다.
void EnterBtn_Click(object sender, Eventargs e)
InputField의 텍스트를 비우고 Controller(해당 텍스트) 메소드를 실행합니다.
후에 InputField에 다시 포커스를 맞춥니다.
void RefreshUserlist()와 void ClientForm_Load()는 사용하지않았습니다.
예외가 일어나는 부분이 꽤 많습니다... VS 디버그 모드로 해당부분 예외 발견 후 처리하는 구문을 많이 쓰셔야 할 수 있습니다.
복사가능한 전체 코드는 아래에 있습니다.
EnterID.cs
using System;
using System.Windows.Forms;
namespace myClient
{
public partial class EnterID : Form
{
string ID;
public EnterID()
{
InitializeComponent();
}
private void IDbtn_Click(object sender, EventArgs e)
{
if(IDInputField.Text.Equals(string.Empty))
{
}
else
{
ID = IDInputField.Text;
ClientForm clientform = new ClientForm(ID);
this.Hide();
clientform.ShowDialog();
}
}
private void IDInputField_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return) IDbtn_Click(sender, e);
}
}
}
ClientForm.cs
using System;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Threading;
namespace myClient
{
public partial class ClientForm : Form
{
string ID;
NetworkStream stream = default(NetworkStream);
TcpClient client = new TcpClient();
public ClientForm(string ID)
{
this.ID = ID;
InitializeComponent();
}
void Connect(string s)
{
char split = ' ';
string[] parsedIP = s.Split(split); // 1 : client, 2 : server, 3 : server Port
try
{
IPEndPoint clientAddr = new IPEndPoint(IPAddress.Parse(parsedIP[1]), 0);
IPEndPoint serverAddr = new IPEndPoint(IPAddress.Parse(parsedIP[2]), Int32.Parse(parsedIP[3]));
client = new TcpClient(clientAddr);
client.Connect(serverAddr);
stream = client.GetStream();
Display("Chat Server Connected...");
}
catch(Exception e)
{
Display("Failed to Connect...");
}
if(!client.Connected)
{
MessageBox.Show("usage : /connect 클라이언트IP 서버IP 서버PORT");
InputField.Text = string.Empty;
InputField.Focus();
}
else
{
byte[] buffer = Encoding.Default.GetBytes(ID);
stream.Write(buffer, 0, buffer.Length);
Thread clientThread = new Thread(Receiver);
clientThread.IsBackground = true;
clientThread.Start();
}
}
void Display(string msg)
{
CheckForIllegalCrossThreadCalls = false;
ChatLog.AppendText(msg+"\r\n");
ChatLog.Select(ChatLog.Text.Length, 0);
ChatLog.ScrollToCaret();
}
void Receiver()
{
try
{
while (true)
{
int bufferSize = client.ReceiveBufferSize;
byte[] buffer = new byte[bufferSize];
int bytes = stream.Read(buffer, 0, buffer.Length);
string msg = Encoding.Default.GetString(buffer, 0, bytes);
if(!isControlMsg(msg)) Display(msg);
}
}
catch(IOException e)
{
//
}
}
bool isControlMsg(string msg)
{
bool isCtrl = true;
if (msg.StartsWith("**userlist** "))
{
ChatterList.Items.Clear();
char split = ' ';
string[] userlist = msg.Split(split);
foreach(string s in userlist)
{
if (s.StartsWith("**")) continue;
ChatterList.Items.Add(s);
}
}
else isCtrl = false;
return isCtrl;
}
void RefreshUserlist(string[] ul)
{
}
void Sender(string s)
{
byte[] buffer = Encoding.Default.GetBytes(s);
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
}
void Controller(string s)
{
if(s.StartsWith("/connect "))
{
Connect(s);
}
else if(!client.Connected)
{
MessageBox.Show("서버에 먼저 연결해주세요.");
InputField.Text = string.Empty;
InputField.Focus();
}
else if(s.Equals("/exit"))
{
Disconnect();
}
else
{
Sender(s);
}
}
void Disconnect()
{
byte[] buffer = Encoding.Default.GetBytes("/exit");
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
stream.Close();
client.Close();
Application.ExitThread();
this.Close();
}
void Disconnect(object sender, EventArgs e)
{
byte[] buffer = Encoding.Default.GetBytes("/exit");
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
stream.Close();
client.Close();
Application.ExitThread();
this.Close();
}
private void InputField_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return) EnterBtn_Click(sender, e);
}
private void EnterBtn_Click(object sender, EventArgs e)
{
string input = InputField.Text;
Controller(input);
InputField.Text = string.Empty;
InputField.Focus();
}
private void ClientForm_Load(object sender, EventArgs e)
{
}
}
}
'C# > WinForm' 카테고리의 다른 글
C# TCP - 1:N 윈폼 채팅 서버/클라이언트 - 3. 실행 화면 (4) | 2020.03.27 |
---|---|
C# TCP - 1:N 윈폼 채팅 서버/클라이언트 - 1. 서버 (0) | 2020.03.27 |
C# TCP - 1:N 윈폼 채팅 서버/클라이언트 - 0. 준비 (0) | 2020.03.27 |