C# 소켓, 스레드를 이용한 채팅 프로그램
(C#을 처음 시작했기 때문에, 틀리거나 비효율적인 부분이 많이 있을 수 있습니다. 알려주시면 수정하겠습니다.)
C#이 Java와 너무 비슷해서, Java로 배운 네트워크/스레드 프로그래밍 기술(?)로 만든 엄청 간단한 채팅 프로그램이다.
Socket 통신에 관한 내용은 다른 블로그들에 너무너무 설명이 잘 돼있으니 참고하자!
작동 방식은 아래와 같다.
1. A, B, C 접속
2. A가 메시지를 보냄 => 서버에 전송 => 서버가 B, C에게 A의 메시지를 보냄
** 클라이언트끼리의 통신이 아니고, 클라이언트들과 서버의 통신이다.
테스트방법(사용방법)은
1. 서버프로그램과 클라이언트(2~3개)프로그램들을 차례대로 실행한다.(서버부터 실행)
**실행 == dotnet run
2. 모든 클라이언트 프로그램에 id/client1 처럼 아이디(client1)를 입력한다. (아이디는 서로 다르게)
3. 한 클라이언트 프로그램에 addMsg/입력할메시지 라고 입력하고, 다른 프로그램들의 변화를 관찰한다.
client와 server 모두 아래와 비슷하게 while문을 돌며 각각 server측 / client측의 입력을 계속 받도록 했고,
외부(server 혹은 client)로부터 입력을 받을 때, 다른 작업(server 혹은 client로의 전송)을 할 수 있도록 Thread를 생성하여 실행했다.
아래는 client의 source code 중 일부이다.
(new Thread(new ThreadStart(() =>
{
while(true)
{
String line = "";
while(line.Equals(""))
{
line = reader.ReadLine();
if(line == null)
{
Console.WriteLine("서버와의 연결이 끊어졌습니다.");
return;
}
}
String[] command = line.Split("/");
if(command[0].Equals("addMsg"))
{
Console.WriteLine(command[1] + "/" + command[2]);
}
}
}))).Start();
아래는 전체 source code이다.
Server
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
namespace server
{
class Program
{
public const int port = 50000;
public static ArrayList clientList = new ArrayList();
static void Main(string[] args)
{
new Program();
}
public Program()
{
TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
tcpListener.Start();
while(true)
{
Socket client = tcpListener.AcceptSocket();
IPEndPoint ip = (IPEndPoint) client.RemoteEndPoint;
Console.WriteLine("주소 {0}에서 접속", ip);
ClientListener clientThread = new ClientListener(client);
clientList.Add(clientThread);
}
}
}
class ClientListener
{
String id;
Socket client;
System.IO.StreamReader reader;
System.IO.StreamWriter writer;
public ClientListener(Socket client)
{
this.client = client;
NetworkStream networkStream = new NetworkStream(client);
this.reader = new System.IO.StreamReader(networkStream);
this.writer = new System.IO.StreamWriter(networkStream);
(new Thread(new ThreadStart(Run))).Start();
}
private void Run()
{
while(true)
{
String line = "";
while(line.Equals(""))
{
line = reader.ReadLine();
if(line == null)
{
Program.clientList.Remove(this);
Console.WriteLine(this.id + "접속 종료");
return;
}
}
Console.WriteLine(client.RemoteEndPoint + "-send/" + line);
String[] command = line.Split("/");
if(command[0].Equals("addMsg"))
{
foreach(object clientThread in Program.clientList)
{
ClientListener client = (ClientListener) clientThread;
Console.WriteLine(client.id);
if(!client.Equals(this))
{
NetworkStream networkStream = new NetworkStream(client.client);
System.IO.StreamWriter writer = new System.IO.StreamWriter(networkStream);
writer.WriteLine("addMsg/" + this.id + "/" + command[1]);
writer.Flush();
}
}
}
else if(command[0].Equals("id"))
{
this.id = command[1];
}
}
}
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if ((obj == null) || ! this.GetType().Equals(obj.GetType()))
{
return false;
}
else {
ClientListener other = (ClientListener) obj;
return (this.id == other.id);
}
}
public override int GetHashCode() { return 0; } // 나중에 알아보기
}
}
Client
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace client
{
class Program
{
static void Main(string[] args)
{
TcpClient server;
try
{
server = new TcpClient("127.0.0.1", 50000);
}
catch (Exception)
{
Console.WriteLine("서버와의 연결이 끊어졌습니다.");
return;
}
NetworkStream networkStream = server.GetStream();
System.IO.StreamReader reader = new System.IO.StreamReader(networkStream);
System.IO.StreamWriter writer = new System.IO.StreamWriter(networkStream);
(new Thread(new ThreadStart(() =>
{
while(true)
{
String line = "";
while(line.Equals(""))
{
line = reader.ReadLine();
if(line == null)
{
Console.WriteLine("서버와의 연결이 끊어졌습니다.");
return;
}
}
String[] command = line.Split("/");
if(command[0].Equals("addMsg"))
{
Console.WriteLine(command[1] + "/" + command[2]);
}
}
}))).Start();
String line = "";
while(!line.Equals("quit"))
{
line = Console.ReadLine();
writer.WriteLine(line);
writer.Flush();
}
}
}
}