인터넷 소스 참고하면서 채팅 프로그램을 만들어 보았습니다.
WpfApplication_chat.7z
WpfApplication_Client.7z
뭐, 여러가지 테스트를 거치지 않았으며, 동작되는 것만 확인 한 정도입니다.
서버측 소스에서 중점적으로 봐야 할 부분이라면,,,
m_threadListen = new
Thread(new
ThreadStart(listen));
m_threadListen.Start(); |
스레드를 생성해서 클라이언트의 접속을 기다립니다. 그렇지 않으면 서버가 클라이언트가 올때까지 아무런 일을 할 수 없으니까요.
TcpClient client;
client = m_server.AcceptTcpClient(); |
클라이언트의 접속을 기다립니다.
Thread threadReceive = new
Thread(new
ParameterizedThreadStart(receive));
threadReceive.Start(client); |
접속한 클라이언트와의 통신을 위해 스레드를 생성합니다.
이때 접속한 클라이언트의 정보를 전달하기 위해서 ParameterizedThreadStart 를 사용합니다.
public
void receive(object p_client) |
해당 스레드에서 파라미터를 받을 때에는 object 타입으로 받아야 하더라구요.
if (stream.CanRead)
{
String clientMsg = reader.ReadLine();
} |
스트림을 읽을 수 있는지 확인한 후에, ReadLine() 을 통해서 받은 메시지를 읽습니다.
foreach (TcpClient client in m_clients)
{
StreamWriter writer = new
StreamWriter(client.GetStream());
writer.WriteLine(sendingMsg);
writer.Flush();
} |
서버에서 모든 클라이언트에 메시지를 보내기 위해서 저장해놓은 클라이언트 정보를 이용해서 메시지를 보냅니다. WriteLine()을 통해서 보냅니다. Write() 함수를 쓰니 전송이 안되더라구요. '\n'을 붙이면 됬을까요?
서버소스
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
namespace WpfApplication_chat
{
/// <summary>
/// MainWindow.xaml에¯¢® 대¥e한N 상ío호¡Ì 작U용¯e 논øi리¬¢ç
/// </summary>
public partial class MainWindow : Window
{
Thread m_threadListen;
TcpListener m_server;
ArrayList m_clients;
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
this.Closed += new EventHandler(MainWindow_Closed);
}
void MainWindow_Closed(object sender, EventArgs e)
{
if (m_server != null)
m_server.Stop();
if (m_threadListen != null)
m_threadListen.Abort();
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
m_clients = new ArrayList();
startServer();
}
private void startServer()
{
m_threadListen = new Thread(new ThreadStart(listen));
m_threadListen.Start();
}
private void listen()
{
int port = 5432;
m_server = new TcpListener(IPAddress.Any, port);
m_server.Start();
showMsg("#server started");
while (true)
{
TcpClient client;
client = m_server.AcceptTcpClient();
m_clients.Add(client);
int clientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
showMsg("[" + clientPort + "] 클¡þ라Òo이I언ú©£트¡¢ç와¯I 연¯¡þ결Æa 되ìC었úu습öA니¥I다¥U.");
Thread threadReceive = new Thread(new ParameterizedThreadStart(receive));
threadReceive.Start(client);
}
}
public void receive(object p_client) // 파¡A라Òo미öI터I 타¢¬입O은¨¬ object 로¤I 해¨ª주O어úi야ú©¬ 한N다¥U.
{
TcpClient client = (TcpClient)p_client;
NetworkStream stream;
stream = client.GetStream();
StreamReader reader;
reader = new StreamReader(stream);
StreamWriter writer;
writer = new StreamWriter(stream);
int clientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
try
{
while (true)
{
Thread.Sleep(1);
if (stream.CanRead)
{
String clientMsg = reader.ReadLine();
if (clientMsg.Length > 0)
{
showMsg("[" + clientPort + "] : " + clientMsg);
}
}
}
}
catch (System.Exception ex)
{
showMsg("["+clientPort + "] 클¡þ라Òo이I언ú©£트¡¢ç와¯I 연¯¡þ결Æa이I 종¨ú료¤a되ìC었úu습öA니¥I다¥U.");
m_clients.Remove(client);
}
}
private delegate void INVOKE_MSG(String msg);
private void showMsg(string msg)
{
INVOKE_MSG invokeShowMsg = new INVOKE_MSG(showMsgToTextBox);
this.Dispatcher.Invoke(invokeShowMsg, msg);
}
private void showMsgToTextBox(String msg)
{
String time = System.DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss");
tbMsg.Text += time + ": " + msg + "\n";
}
private void tbMsg_SizeChanged(object sender, SizeChangedEventArgs e)
{
sv.ScrollToBottom();
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
String sendingMsg = txtSendMsg.Text;
if (sendingMsg.Length > 0)
{
showMsg("[me] " + sendingMsg);
foreach (TcpClient client in m_clients)
{
StreamWriter writer = new StreamWriter(client.GetStream());
writer.WriteLine(sendingMsg);
writer.Flush();
}
txtSendMsg.Text = String.Empty;
}
}
}
}
클라이언트측 소스에서 볼 부분은
m_client.Connect(ip, port); |
Connect 함수를 통해서 서버에 접속합니다. IP, Port 는 미리 알고 있어야 겠죠.
Thread threadReceive = new
Thread(new
ParameterizedThreadStart(receive));
threadReceive.Start(m_client); |
서버측 메시지를 받기위한 스레드를 생성합니다.
private
delegate
void
INVOKE_BTN(Boolean canConnect);
private
void changeChatBtnsCanConnect(Boolean canConnect)
{
INVOKE_BTN invokeChangeBtn = new
INVOKE_BTN(changeChatBtns);
this.Dispatcher.Invoke(invokeChangeBtn, canConnect);
}
private
void changeChatBtns(bool canConnect)
{
btnConnect.IsEnabled = canConnect;
btnSend.IsEnabled = !canConnect;
}
|
주 스레드가 아닌 스레드에서 UI 변경을 위해 INVOKE 를 사용합니다.
서버측과 동일하게 ReadLine() / WriteLine() 을 통해서 통신을 하면 됩니다.
클라이언트 소스
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Net;
namespace WpfApplication_client
{
/// <summary>
/// MainWindow.xaml에¯¢® 대¥e한N 상ío호¡Ì 작U용¯e 논øi리¬¢ç
/// </summary>
public partial class MainWindow : Window
{
TcpClient m_client;
StreamWriter m_writer;
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
this.Closed += new EventHandler(MainWindow_Closed);
}
void MainWindow_Closed(object sender, EventArgs e)
{
if (m_client != null)
{
m_client.Close();
}
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
setDefaultIp();
}
private void tbMsg_SizeChanged(object sender, SizeChangedEventArgs e)
{
sv.ScrollToBottom();
}
private void btnConnect_Click(object sender, RoutedEventArgs e)
{
if (txtIp.Text == "")
{
MessageBox.Show("서ù¡©버öo IP 주O소ùO를¬| 입O력¤A해¨ª 주O세ù¨ù요¯a");
setDefaultIp();
return;
}
String ip = txtIp.Text;
int port = 5432;
m_client = new TcpClient();
try
{
m_client.Connect(ip, port);
showMsg("서ù¡©버öo와¯I 연¯¡þ결Æa 되ìC었úu습öA니¥I다¥U..");
changeChatBtnsCanConnect(false);
NetworkStream stream;
stream = m_client.GetStream();
m_writer = new StreamWriter(stream);
Thread threadReceive = new Thread(new ParameterizedThreadStart(receive));
threadReceive.Start(m_client);
}
catch (System.Exception ex)
{
showMsg("연¯¡þ결Æa할O 수ùo 없ú©ª습öA니¥I다¥U.");
changeChatBtnsCanConnect(true);
}
}
private delegate void INVOKE_BTN(Boolean canConnect);
private void changeChatBtnsCanConnect(Boolean canConnect)
{
INVOKE_BTN invokeChangeBtn = new INVOKE_BTN(changeChatBtns);
this.Dispatcher.Invoke(invokeChangeBtn, canConnect);
}
private void changeChatBtns(bool canConnect)
{
btnConnect.IsEnabled = canConnect;
btnSend.IsEnabled = !canConnect;
}
public void receive(object p_client) // 파¡A라Òo미öI터I 타¢¬입O은¨¬ object 로¤I 해¨ª주O어úi야ú©¬ 한N다¥U.
{
TcpClient client = (TcpClient)p_client;
NetworkStream stream;
stream = client.GetStream();
StreamReader reader;
reader = new StreamReader(stream);
int clientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
try
{
while (true)
{
if (stream.CanRead)
{
String clientMsg = reader.ReadLine();
if (clientMsg.Length > 0)
{
showMsg("[" + clientPort + "] sent : " + clientMsg);
}
}
Thread.Sleep(1);
}
}
catch (System.Exception ex)
{
showMsg("[" + clientPort + "] 서ù¡©버öo와¯I 연¯¡þ결Æa이I 종¨ú료¤a되ìC었úu습öA니¥I다¥U.");
changeChatBtnsCanConnect(true);
}
}
private delegate void INVOKE_MSG(String msg);
private void showMsg(string msg)
{
INVOKE_MSG invokeShowMsg = new INVOKE_MSG(showMsgToTextBox);
this.Dispatcher.Invoke(invokeShowMsg, msg);
}
private void showMsgToTextBox(String msg)
{
// 시öA간Æ¡Ì 얻úo기¾a
String time = System.DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss");
tbMsg.Text += time + ": " + msg + "\n";
}
private void setDefaultIp()
{
txtIp.Text = "127.0.0.1";
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
String sendingMsg = txtSendMsg.Text;
if (sendingMsg.Length > 0)
{
showMsg("[me] " + sendingMsg);
m_writer.WriteLine(sendingMsg);
m_writer.Flush();
txtSendMsg.Text = String.Empty;
}
}
}
}
댓글