자바/네트워킹
소켓 프로그래밍: 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
( 아이디어는 아래와 같다. )
< 서버 >
메서드 | 설명 |
메인 클래스 생성자() | 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)