Socket 클래스이용한채팅프로그램 스트림방식의채팅프로그램 헬퍼클래스방식의채팅프로그램 순천향대학교컴퓨터학부이상정 1 학습내용 Socket 클래스이용한채팅프로그램 스트림방식의채팅프로그램 헬퍼클래스방식의채팅프로그램 순천향대학교컴퓨터학부이상정 2
Socket 클래스이용한채팅프로그램 순천향대학교컴퓨터학부이상정 3 1:1 채팅프로그램 한프로그램이동시에서버와클라이언트로동작 프로그램시작시서버로동작 서버소켓생성하고상대방접속요청대기 채팅을위한연결요청시클라이언트로동작 다른쪽은상대방이열어놓은서버소켓에접속 Network 클래스를추가하여통신처리를전담 프로젝트이름 : MainChat 컨트롤을배치하고속성을설정 순천향대학교정보기술공학부이상정 4
실행결과 순천향대학교컴퓨터학부이상정 5 실행결과 순천향대학교컴퓨터학부이상정 6
사용자인터페이스 컨트롤을배치하고속성을설정 컨트롤속성값 Name Form1 Form Text 1:1 채팅프로그램 Ver 1.0 FormBorderStyle FixedSingle TextBox Name txt_ ip Button Name btn_connect Text 연결 Name txt_info TextBox Multiline True ReadOnly True TextBox Name txt_input 순천향대학교컴퓨터학부이상정 7 Form1.cs: 네임스페이스, 변수추가 Form1.cs 소스파일열고 (Form 선택후더블클릭 ) 네임스페이스와멤버변수추가 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace MainChat public partial class Form1 : Form // 채팅처리를전담하는 Network 클래스객체변수선언 private Network net = null; private Thread server_th = null; // 채팅서버스레드선언 private string my_ip = null; // 자신의 ip 주소를기록할변수 public Form1() InitializeComponent(); net = new Network(this); // 네트워크클래스객체생성 순천향대학교컴퓨터학부이상정 8
Form1.cs: 이벤트처리기추가 (1) Form1 의이벤트처리기추가 Form 을선택한후이벤트처리기에서 Load 와 FormClosed 이벤트 처리기추가 Load 이벤트처리기 채팅서버로동작하게하는쓰레드를생성하고시작 FormClosed 이벤트처리기 생성된쓰레드를종료 순천향대학교컴퓨터학부이상정 9 Form1.cs: 이벤트처리기추가 // 채팅창이출력되기직전에실행되는이벤트 private void Form1_Load(object sender, EventArgs e) my_ip = net.get_myip(); // 자신의 ip 정보알아내기 // 채팅서버를시작시키는쓰레드를생성 server_th = new Thread(new ThreadStart(net.ServerStart)); server_th.start(); // 채팅서버시작 // 채팅창이닫힌후발생하는이벤트 ( 프로그램이종료될때 ) private void Form1_FormClosed(object sender, FormClosedEventArgs e) if (btn_connect.text == " 접속중...") // 클라이언트로수행중 net.disconnect(); // 채팅서버와연결되어있으면연결끊기 else // 서버로수행중 net.serverstop(); // 채팅서버실행중지 if (server_th.isalive) server_th.abort(); //ServerStart 스레드를종료 catch(exception ex) MessageBox.Show(ex.Message); Message); // 예외메시지출력 순천향대학교컴퓨터학부이상정 10
Form1.cs: 버튼이벤트처리기 [ 연결 ] 버튼에대한 [Click] 이벤트처리기를작성 프로그램이클라이언트로동작 private void btn_connect_click(object Click(object sender, EventArgs e) if (btn_connect.text == " 연결 ") // 채팅서버에접속할경우 string ip = txt_ip.text.trim(); // 접속할서버 ip 주소가져오기 if (ip == "") // 접속할채팅서버의 ip 주소를입력하지않았다면 MessageBox.Show(" 아이피번호를입력하세요!"); // 에러메시지출력 return ; if (!net.connect(ip)) // 채팅서버에접속시도 MessageBox.Show(" 서버아이피번호가틀리거나 r n 서버가작동중이지않습니다."); else btn_connect.text =" 접속중..."; // 접속이성공하면버튼문자열변경 else // 채팅을종료할경우 net.disconnect(); // 채팅서버와연결을끊음 btn_connect.text = " 연결 "; // 버튼문자열을 접속중.. 에서 연결 로변경 순천향대학교컴퓨터학부이상정 11 Form1.cs: txt_input 이벤트처리기 txt_input 텍스트박스의 KeyDown 이벤트처리기추가 채팅메시지를입력하고엔터를치면상대컴퓨터로입력한메시지를전송 Form1 클래스에멤버메서드인 Add_MSG 를추가 채팅문자열을텍스트박스 txt_info 에추가 private void txt_input_keydown(object sender, KeyEventArgs e) // 엔터키가눌리면문자열메시지를상대방에게전송 if ( e.keycode == Keys.Enter ) string msg = txt_input.text.trim(); Add_MSG("[ 본인 ] " + msg); net.send(msg); // 메시지전송 txt_input.text = ""; // 다음메시지입력을위해비워둔다. txt_input.focus(); // txt_input 텍스트박스에초점맞춤 public void Add_MSG(string msg) txt_info.appendtext(msg info.appendtext(msg+" r n"); // 채팅문자열출력 txt_info.scrolltocaret(); // 텍스트박스의내용을현재캐럿위치까지스크롤 txt_input.focus(); 순천향대학교컴퓨터학부이상정 12
Network 클래스 소켓통신을전담처리하는 Network 클래스작성 [ 솔루션탐색기 ] 에서 MainChat 프로젝트를선택하고마우스오른쪽버튼을클릭한후 [ 추가 ]-[ 새항목추가..] 를선택 새항목추가창에서 [ 클래스 ] 템플릿을선택하고이름에 Network.cs 라고입력한후 [ 열기 ] 버튼을클릭하고프로그램작성 Network 클래스실행동작 채팅서버로실행된다면 ServerStart 메서드와 ServerStop 메서드를사용 클라이언트로사용된다면 Connect 메서드와 DisConnect 메서드를사용 모든데이터는 Receive, Send 메서드를통해바이트단위로수신 / 송신 순천향대학교컴퓨터학부이상정 13 프로그램구성도 순천향대학교컴퓨터학부이상정 14
Network.cs 소스 using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Text; // 네트워크처리 // 소켓처리 // 쓰레드처리 // 문자열처리 namespace MainChat public class Network Form1 wnd = null; // 채팅창객체변수 Socket server = null; // 채팅서버 ( 접속을받는소켓 ) 로사용할소켓 Socket client = null; // 서버일경우통신소켓, 클라이언트일경우접속및통신용소켓 Thread th = null; // 쓰레드처리 public Network(Form1 wnd) // 생성자 this.wnd = wnd; // NetWork 클래스에서 Form1의멤버를사용하도록허용 순천향대학교컴퓨터학부이상정 15 // 채팅서버시작 : 클라이언트접속을받고메시지를수신 public void ServerStart() // 서버포트번호를 7000번으로지정 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 7000); server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); server.bind(ipep); // 소켓과서버 ip, 포트번호를바인드 server.listen(10); // 클라이언트접속을대기 wnd.add_msg(" 채팅서버시작..."); client = server.accept(); // 클라이언트가접속할때활성화 // 접속한클라이언트 ip 주소를출력 IPEndPoint ip = (IPEndPoint)client.RemoteEndPoint; wnd.add_msg(ip.address + " 접속..."); //Receive 메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); // 채팅서버에서예외가발생하면 // 예외메시지 txt_info에출력 순천향대학교컴퓨터학부이상정 16
// 채팅서버중지 public void ServerStop() if (client!= null) // 클라이언트가접속된상태라면 if (client.connected) client.close(); // 통신소켓을닫습니다. if (th.isalive) // Receive 스레드가실행중이라면 th.abort(); // 쓰레드종료 server.close(); // 서버소켓을닫습니다. // 예외메시지출력 순천향대학교컴퓨터학부이상정 17 // 채팅서버와연결 public bool Connect(string ip) // 접속할채팅서버 ip 주소와포트번호를지정 IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), 7000); client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.connect(ipep); // 채팅서버에접속을시도 wnd.add_msg(ip dadd +" 서버에접속성공..."); // 채팅문자열을수신하는메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); return true; // 접속성공하면 true 값을반환 // 채팅서버접속에실패하면예외메시지를출력 return false; // 접속실패했으면 false 값을반환 순천향대학교컴퓨터학부이상정 18
// 채팅서버와연결종료 public void DisConnect() if (client!= null) if (client.connected) client.close(); // 채팅서버와연결되어있다면 // 채팅서버와의연결을단절 if (th.isalive) th.abort(); //Receive 메서드쓰레드를중지 wnd.add_msg(" 채팅서버연결종료!"); // 채팅서버연결해제와쓰레드종료시예외가발생하면 // 예외메시지출력 순천향대학교컴퓨터학부이상정 19 // 상대방에게데이터송신 public void Send(string msg) if (client.connected) // 문자열을바이트배열형태로변경합니다. // 상대방과연결되어있으면 byte[] data = Encoding.Default.GetBytes(msg); SendData(data); // 바이트배열을상대방에전송 else // 상대방과연결되어있지않다면 wnd.add_msg(" 메시지전송실패!"); dadd M 순천향대학교컴퓨터학부이상정 20
객체지향윈도즈프로그래밍 private void SendData(byte[], Visual C# data) int offset = 0; // 버퍼내위치 int size = data.length; // 전송할바이트배열의크기 int left_data = size; // 남은데이터량 int send_data = 0; // 전송된데이터크기 // 전송할실제데이터의크기전달 bt[]d byte[] data_size = new byte[4]; // 정수형태로데이터크기전송 data_size = BitConverter.GetBytes(size); send_data = client.send(data_size); // 실제데이터전송 while (offset < size) send_data ddt = client.send(data, t offset, left_data, t SocketFlags.None); offset += send_data; left_data -= send_data; // 데이터전송중예외가발생하면에러메시지출력 Message); 순천향대학교컴퓨터학부이상정 21 // 상대방의데이터수신 public void Receive() // 상대방과연결되었다면 while (client!= null && client.connected) //ReceiveData 메서드를사용해바이트단위로데이터를읽어옵니다. byte[] data = ReceiveData(); wnd.add_msg( MSG("[ 상대방 ]" + Encoding.Default.GetString(data)); dadd M private byte[] ReceiveData() int offset = 0; // 버퍼내위치 int size = 0; // 수신할데이터크기 int left_data = 0; // 남은데이터크기 int recv_data = 0; // 수신한데이터크기 순천향대학교컴퓨터학부이상정 22
// 수신할데이터크기알아내기 byte[] data_size = new byte[4]; recv_data = client.receive(data_size, 0, 4, SocketFlags.None); size = BitConverter.ToInt32(data_size, 0); left_data = size; byte[] data = new byte[size]; // 바이트배열생성 // 서버에서전송한실제데이터수신 while (offset < size) // 상대방이전송한데이터를읽어옴 recv_data = client.receive(data, offset, left_data, SocketFlags.None); if (recv_data == 0) break; offset += recv_data; left_data -= recv_data; return data; // 데이터수신중예외가발생하면에러메시지출력 return null; 순천향대학교컴퓨터학부이상정 23 // IP 주소구하기 public string Get_MyIP() IPHostEn host = Dns.Resolve(Dns.GetHostName()); // 첫번째ip 주소를사용 string myip = host.addresslist[0].tostring(); return myip; 순천향대학교컴퓨터학부이상정 24
스트림방식의채팅프로그램 순천향대학교컴퓨터학부이상정 25 스트림방식채팅프로그램으로작성 프로젝트이름 : MainChat1 Form1 클래스는앞에서작성한소켓방식채팅프로그램과 코드가동일 통신을전담처리하는 Network 클래스는소켓대신에스트림 을사용하여통신하도록수정 스트림방식채팅은소켓방식채팅프로그램에비해구현이용이 NetworkStream 클래스를통해데이터가문자열단위로입출력 순천향대학교컴퓨터학부이상정 26
순천향대학교컴퓨터학부이상정 27 Network.cs 소스 using System; using System.Net; // 네트워크처리 using System.Net.Sockets; // 소켓처리 using System.Threading; // 쓰레드처리 using System.Text; // 문자열처리 using System.IO; // ver 2.0 추가부분 namespace MainChat1 public class Network Form1 wnd = null; Socket server = null; Socket client = null; Thread th = null; // 채팅창객체변수 // 채팅서버 ( 접속을받는소켓 ) 로사용할소켓 // 서버일경우통신소켓, 클라이언트일경우접속및통신용소켓 // 쓰레드처리 // Ver 2.0에추가된부분 NetworkStream stream = null; StreamReader reader = null; StreamWriter writer = null; // 네트워크스트림 // 읽기문자스트림 // 쓰기문자스트림 public Network(Form1 wnd) // 생성자 this.wnd = wnd; // NetWork 클래스에서 Form1의멤버를사용하도록허용 순천향대학교컴퓨터학부이상정 28
객체지향윈도즈프로그래밍 // 채팅서버시작, Visual : 클라이언트 C# 접속을받고메시지를수신 public void ServerStart() // 서버포트번호를 7000번으로지정 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 7000); server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); server.bind(ipep); // 소켓과서버 ip, 포트번호를바인드 server.listen(10); // 클라이언트접속을대기 wnd.add_msg(" 채팅서버시작..."); client = server.accept(); // 클라이언트가접속할때활성화 // 접속한클라이언트 ip 주소를출력 IPEndPoint ip = (IPEndPoint)client.RemoteEndPoint; wnd.add_msg(ip.address +" 접속..."); // Ver 2.0에추가된부분, 서버에서송수신을위한스트림객체를생성 stream = new NetworkStream(this.client); reader = new StreamReader(stream); writer = new StreamWriter(stream); //Receive 메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); // 채팅서버에서예외가발생하면 // 예외메시지 txt_info에출력 순천향대학교컴퓨터학부이상정 29 // 채팅서버중지 public void ServerStop() if (client!= null) if (client.connected) // Ver 2.0에추가된부분 reader.close(); writer.close(); stream.close(); // 클라이언트가접속된상태라면 //streamreader 종료 //streamwriter 종료 //networkstream 종료 client.close(); // 통신소켓을닫습니다. if (th.isalive) // Receive 스레드가실행중이라면 th.abort(); // 쓰레드종료 server.close(); // 서버소켓을닫습니다. // 예외메시지출력 순천향대학교컴퓨터학부이상정 30
// 채팅서버와연결 public bool Connect(string ip) // 접속할채팅서버 ip 주소와포트번호를지정 IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), 7000); client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.connect(ipep); // 채팅서버에접속을시도 wnd.add_msg(ip + " 서버에접속성공..."); // Ver 2.0에추가된부분 stream = new NetworkStream(this.client); reader = new StreamReader(stream); writer = new StreamWriter(stream); // 채팅문자열을수신하는메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); return true; return false; 순천향대학교컴퓨터학부이상정 31 // 접속성공하면 true 값을반환 // 채팅서버접속에실패하면예외메시지를출력 // 접속실패했으면 false 값을반환 // 채팅서버와연결종료 public void DisConnect() if (client!= null) if (client.connected) // Ver 2.0에추가된부분 reader.close(); writer.close(); stream.close(); client.close(); // 채팅서버와연결되어있다면 //streamreader 닫기 //streamwriter 닫기 //networkstream 닫기 // 채팅서버와의연결을단절 if (th.isalive) th.abort(); wnd.add_msg(" 채팅서버연결종료!"); // 채팅서버연결해제와쓰레드종료시예외가발생하면 순천향대학교컴퓨터학부이상정 32 // 예외메시지출력 //Receive 메서드쓰레드를중지
// 상대방에게데이터송신 public void Send(string msg) if (client.connected) // 상대방과연결되어있으면 // Ver 2.0에서변경된부분 writer.writeline(msg); // 문자열메시지전송 writer.flush(); else // 상대방과연결되어있지않다면 wnd.add_msg(" 메시지전송실패!"); 순천향대학교컴퓨터학부이상정 33 객체지향윈도즈프로그래밍 // 상대방의데이터, Visual 수신 C# public void Receive() // Ver 2.0에서변경된부분 while( client.connected ) string msg = reader.readline(); // 라인단위로문자열읽어오기 this.wnd.add_msg("[ 상대방 ]"+msg); // IP 주소구하기 public string Get_MyIP() IPHostEn host = Dns.Resolve(Dns.GetHostName()); // 첫번째 ip 주소를사용 string myip = host.addresslist[0].tostring(); return myip; 순천향대학교컴퓨터학부이상정 34
헬퍼클래스방식의채팅프로그램 순천향대학교컴퓨터학부이상정 35 using System; using System.Net; // 네트워크처리 using System.Net.Sockets; // 소켓처리 using System.Threading; // 쓰레드처리 using System.Text; // 문자열처리 using System.IO; // ver 2.0 추가부분 Network.cs 소스 namespace MainChat2 public class Network Form1 wnd =null; // 채팅창객체변수 Thread th = null; // 쓰레드처리 // Ver 2.0에추가된부분 NetworkStream stream = null; // 네트워크스트림 StreamReader reader = null; // 읽기문자스트림 StreamWriter writer = null; // 쓰기문자스트림 // Ver 3.0에수정된부분 TcpListener server = null; // 서버소켓 ( 접속을받는소켓 ) TcpClient client = null; // 통신소켓 public Network(Form1 wnd) // 생성자 this.wnd = wnd; // NetWork 클래스에서 Form1의멤버를사용하도록허용 순천향대학교컴퓨터학부이상정 36
// 채팅서버시작 : 클라이언트접속을받고메시지를수신 public void ServerStart() // Ver 3.0에수정된부분 server = new TcpListener(7000); server.start(); // 채팅서버실행 wnd.add_msg(" 채팅서버시작..."); // Ver 3.0에수정된부분 // 채팅클라이언트가접속하면통신소켓반환 client = server.accepttcpclient(); stream = client.getstream(); // 통신소켓에대한스트림구하기 // Ver 2.0에추가된부분, 서버에서송수신을위한스트림객체를생성 reader = new StreamReader(stream); writer = new StreamWriter(stream); //Receive 메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); // 채팅서버에서예외가발생하면 // 예외메시지 txt_info 에출력 순천향대학교컴퓨터학부이상정 37 // 채팅서버중지 public void ServerStop() if (client!= null) // 클라이언트가접속된상태라면 // Ver 3.0에수정된부분 if (reader!= null) reader.close(); //streamreader 종료 if (reader!= null) writer.close(); //streamwriter 종료 if (reader!= null) stream.close(); //networkstream 종료 client.close(); // 통신소켓을닫습니다. if (th.isalive) // Receive 스레드가실행중이라면 th.abort(); // 쓰레드종료 server.close(); // 서버소켓을닫습니다. // 예외메시지출력 순천향대학교컴퓨터학부이상정 38
// 채팅서버와연결 public bool Connect(string ip) // 접속할채팅서버 ip 주소와포트번호를지정 // Ver 3.0에수정된부분 client = new TcpClient(ip, 7000); // 접속할채팅서버 ip 주소와포트번호를지정 wnd.add_msg(ip + " 서버에접속성공..."); // Ver 3.0 에추가된부분 stream = client.getstream(); // Ver 2.0 에추가된부분 reader = new StreamReader(stream); writer = new StreamWriter(stream); // 채팅문자열을수신하는메서드를스레드로생성하고시작 th = new Thread(new ThreadStart(Receive)); th.start(); return true; // 접속성공하면 true 값을반환 // 채팅서버접속에실패하면예외메시지를출력 return false; // 접속실패했으면 false 값을반환 순천향대학교컴퓨터학부이상정 39 // 채팅서버와연결종료 public void DisConnect() if (client!= null) // Ver 3.0에수정된부분 if (reader!= null) reader.close(); if (reader!= null) writer.close(); if (reader!= null) stream.close(); //streamreader 종료 //streamwriter 종료 //networkstream 종료 client.close(); // 채팅서버와의연결을단절 if (th.isalive) th.abort(); wnd.add_msg(" 채팅서버연결종료!"); //Receive 메서드쓰레드를중지 // 채팅서버연결해제와쓰레드종료시예외가발생하면 // 예외메시지출력 순천향대학교컴퓨터학부이상정 40
// 상대방의데이터수신 public void Receive() // Ver 3.0에추가된부분 string msg = null; // Ver 30 3.0 에수정된부분 do msg = reader.readline(); // 문자열읽어오기 this.wnd.add_msg("[ 상대방 ]" + msg); // 문자열출력 while (msg!= null); 순천향대학교컴퓨터학부이상정 41 // 상대방에게데이터송신 public void Send(string msg) writer.writeline(msg); // 문자열메시지전송 writer.flush(); Message); // IP 주소구하기 public string Get_MyIP() IPHostEn host = Dns.Resolve(Dns.GetHostName()); // 첫번째 ip 주소를사용 string myip = host.addresslist[0].tostring(); return myip; 순천향대학교컴퓨터학부이상정 42