자바/네트워킹

소켓 프로그래밍: TCP와 UDP(3)

백_곰 2022. 5. 2. 11:30

3-6. 소켓 프로그래밍을 이해하기 위한 예제(6)

: 채팅 프로그램을 만드는 예제이다.

 

( 아래는 서버 프로그램이다. )

package Networking;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Exercise011 {
	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		Socket socket = null;

		try {
			// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
			serverSocket = new ServerSocket(7777);
			System.out.println("서버가 준비되었습니다.");

			socket = serverSocket.accept();

			Sender   sender   = new Sender(socket);
			Receiver receiver = new Receiver(socket);

			sender.start();
			receiver.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	} // main
} // class

class Sender extends Thread {
	Socket socket;
	DataOutputStream out;
	String name;

	Sender(Socket socket) {
		this.socket = socket;
		try {
			out = new DataOutputStream(socket.getOutputStream());
			name = "["+socket.getInetAddress()+":"+socket.getPort()+"]";
		} catch(Exception e) {}
	}

	public void run() {
		Scanner scanner = new Scanner(System.in);
		while(out!=null) {
			try {
				out.writeUTF(name+scanner.nextLine());		
			} catch(IOException e) {}
		}
	} // run()
}

class Receiver extends Thread {
	Socket socket;
	DataInputStream in;

	Receiver(Socket socket) {
		this.socket = socket;
		try {
			in = new DataInputStream(socket.getInputStream());
		} catch(IOException e) {}

	}

	public void run() {
		while(in!=null) {
			try {
				System.out.println(in.readUTF());
			} catch(IOException e) {}
		}
	} // run
}

 

 

( 아래는 클라이언트 프로그램이다. )

 

package Networking;

import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;

public class Exercise012 {
	public static void main(String[] args) {
		try {
			String serverIp = "127.0.0.1";
            
			// 소켓을 생성하여 연결을 요청한다.
			Socket socket = new Socket(serverIp, 7777); 

			System.out.println("서버에 연결되었습니다.");
			Sender sender = new Sender(socket);
			Receiver receiver = new Receiver(socket);

			sender.start();
			receiver.start();
		} catch(ConnectException ce) {
			ce.printStackTrace();
		} catch(IOException ie) {  
			ie.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();  
		}  
	} // main
} // class

 

 

 

 

3-7. 소켓 프로그래밍을 이해하기 위한 예제(7)

: 멀티 채팅 프로그램을 구현한 예제이다.

 

( 아래는 서버 프로그램이다. )

package Networking;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

public class Exercise013 {
	HashMap clients;
	
	Exercise013() {
		clients = new HashMap();
		Collections.synchronizedMap(clients);
		//동기화처리
	}
	
	public static void main(String args[]) {
		new Exercise013().start();
	} 

	public void start() {
		ServerSocket serverSocket = null;
		Socket socket = null;

		try {
			serverSocket = new ServerSocket(3333);
			System.out.println("서버가 시작되었습니다.");

			while(true) {
				socket = serverSocket.accept();
				System.out.println("["+socket.getInetAddress()+":"+socket.getPort()+"]"+"에서 접속하였습니다.");
				ServerReceiver thread = new ServerReceiver(socket);
				thread.start();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	} // start()

	void sendToAll(String msg) {
		Iterator it = clients.keySet().iterator();
		
		while(it.hasNext()) {
			try {
				DataOutputStream out = (DataOutputStream)clients.get(it.next());
				out.writeUTF(msg);
			} catch(IOException e){}
		} // while
	} // sendToAll
	
	class ServerReceiver extends Thread {
		Socket socket;
		DataInputStream in;
		DataOutputStream out;

		ServerReceiver(Socket socket) {
			this.socket = socket;
			try {
				in  = new DataInputStream(socket.getInputStream());
				out = new DataOutputStream(socket.getOutputStream());
			} catch(IOException e) {}
		}

		public void run() {
			String name = "";
			try {
				name = in.readUTF();
				sendToAll("#"+name+"님이 들어오셨습니다.");

				clients.put(name, out);
				System.out.println("현재 서버접속자 수는 "+ clients.size()+"입니다.");

				while(in!=null) {
					sendToAll(in.readUTF());
				}
			} catch(IOException e) {
				// ignore
			} finally {
				sendToAll("#"+name+"님이 나가셨습니다.");
				clients.remove(name);
				System.out.println("["+socket.getInetAddress() +":"+socket.getPort()+"]"+"에서 접속을 종료하였습니다.");
				System.out.println("현재 서버접속자 수는 "+ clients.size()+"입니다.");
			} // try
		} // run
	} // ReceiverThread
} // class

( readUTF()에서 IOException을 발생시켜 클라이언트 나간 것을 확인한다. )

 

 

( 아래는 클라이언트 프로그램이다. )

package Networking;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.util.Scanner;

public class Exercise014 {
	public static void main(String args[]) {
		if(args.length!=1) {
			System.out.println("USAGE: java TcpIpMultichatClient 대화명");
			System.exit(0);
		}

		try {
			String serverIp = "127.0.0.1";
            // 소켓을 생성하여 연결을 요청한다.
			Socket socket = new Socket(serverIp, 7777); 
			System.out.println("서버에 연결되었습니다.");
			Thread sender   = new Thread(new ClientSender(socket, args[0]));
			Thread receiver = new Thread(new ClientReceiver(socket));

			sender.start();
			receiver.start();
		} catch(ConnectException ce) {
			ce.printStackTrace();
		} catch(Exception e) {}
	} // main

	static class ClientSender extends Thread {
		Socket socket;
		DataOutputStream out;
		String name;

		ClientSender(Socket socket, String name) {
			this.socket = socket;
			try {
				out = new DataOutputStream(socket.getOutputStream());
				this.name = name;
			} catch(Exception e) {}
		}

		public void run() {
			Scanner scanner = new Scanner(System.in);
			try {
				if(out!=null) {
					out.writeUTF(name);
				}	

				while(out!=null) {
					out.writeUTF("["+name+"]"+scanner.nextLine());					}
			} catch(IOException e) {}
		} // run()
	} // ClientSender

	static class ClientReceiver extends Thread {
		Socket socket;
		DataInputStream in;

		ClientReceiver(Socket socket) {
			this.socket = socket;
			try {
				in = new DataInputStream(socket.getInputStream());
			} catch(IOException e) {}
		}

		public void run() {
			while(in!=null) {
				try {
					System.out.println(in.readUTF());
				} catch(IOException e) {}
			}
		} // run
	} // ClientReceiver
} // class

 

이클립스 출력문
이클립스 출력문
cmd 출력문

( 아이디어는 아래와 같다. )

 

< 서버 >

메서드 설명
메인 클래스 생성자() HashMap의 초기화와 HashMap 동기화
main() 생성자 실행과 start() 함수 호출
start() 서버 구동을 위한 작업과 다중 클라이언트를 위한 무한반복문 작업(ServerReceiver)
ServerReceiver 클래스 생성자() 소켓과 DataInputStream과 DataOutputStream 초기화
run() 다중 클라이언트를 위해 쓰레드 구현
sendToAll() 다중 클라이언트에게 메시지를 보내는 메서드(동기화를 이용)



< 클라이언트 >

메서드 설명
main() 이름을 입력했는지 확인과 서버연결, Sender와 Receiver의 쓰레드 실행
 Main 클래스의 static Sender 클래스 Socket, DataOutputStream을 초기화
Sender의 run() 초기 ServerReceiver 클래스에게 자신의 이름을 보냄. 그리고 나서
클라이언트의 채팅할 내용을 사용자 입력한 것을 읽어 서버에게 보냄
Main 클래스의 static Receiver 클래스 Socket, DataInputStream, 이름을 초기화
Receiver의 run() 다른 클라이언트의 내용이나 서버의 내용을 받아서 출력

 

 

 

 

다음장

소켓 프로그래밍: TCP와 UDP(4) (tistory.com)