16.6.1 TCP 소켓 프로그래밍
- 순서
- 서버 프로그램에서 서버소켓을 사용하여 클라이언트의 연결요청 처리 준비
- 클라이언트 프로그램에서 IP와 포트 정보로 소켓을 생성하여 서버에 연결 요청
- 서버소켓이 연결요청을 받으면 새로운 소켓을 생성하여 클라이언트 소켓과 연결
- 서버소켓과 관계없이 서버의 새로운 소켓과 클라이언트 소켓간의 1:1 통신
소켓(socket) - 프로토콜 + IP + 포트.
- InputStream과 OutputStream 보유
16.6.2 Server와 Client 연결 예제
- Server
public class TcpIpServer {
public static void main(String args[]) {
ServerSocket serverSocket = null;
try {
// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
serverSocket = new ServerSocket(7777);
System.out.println(getTime() + "서버가 준비되었습니다.");
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
System.out.println(getTime() + "연결요청을 기다립니다.");
// 서버소켓은 클라이언트의 연결요청이 올 때까지
// 실행을 멈추고 계속 기다린다.
// 클라이언트의 연결요청이 오면 클라이언트 소켓과 통신할
// 새로운 소켓을 생성한다.
//연결대기시간 5초 제한
//5초가 지나면 SocketTimeoutException 발생
//serverSocekt.setSocketTimeout(5*1000);
Socket socket = serverSocket.accept();
System.out.println(getTime() + socket.getInetAddress()
+ "로부터 연결요청이 들어왔습니다.");
// 소켓의 출력스트림을 얻는다.
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
// 원격 소켓(remote socket)에 데이터를 보낸다.
dos.writeUTF("[Notice] Test Message1 from Server.");
System.out.println(getTime() + "데이터를 전송했습니다.");
// 스트림과 소켓을 닫아준다.
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
} // while
} // main
// 현재시간을 문자열로 반환하는 함수
static String getTime() {
SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
return f.format(new Date());
}
}
- Client
public class TcpIpClient {
public static void main(String args[]) {
try {
String serverIp = "127.0.0.1";
System.out.println("서버에 연결중입니다. 서버IP :" + serverIp);
// 소켓을 생성하여 연결을 요청한다.
Socket socket = new Socket(serverIp, 7777);
// 소켓의 입력스트림을 얻는다.
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
// 소켓으로 부터 받은 데이터를 출력한다.
System.out.println("서버로부터 받은 메세지 :" + dis.readUTF());
System.out.println("연결을 종료합니다.");
// 스트림과 소켓을 닫는다.
dis.close();
socket.close();
System.out.println("연결이 종료되었습니다.");
} catch (ConnectException ce) {
ce.printStackTrace();
} catch (IOException ie) {
ie.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} // main
}
16.6.3 쓰레드를 이용한 Server 예제
- 쓰레드를 사용하여 클라이언트의 요청을 병렬처리
public class TcpIpServer4 implements Runnable {
ServerSocket serverSocket;
Thread[] threadArr;
public static void main(String args[]) {
// 5개의 쓰레드를 생성하는 서버를 생성한다.
TcpIpServer4 server = new TcpIpServer4(5);
server.start();
} // main
public TcpIpServer4(int num) {
try {
// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
serverSocket = new ServerSocket(7777);
System.out.println(getTime()+"서버가 준비되었습니다.");
threadArr = new Thread[num];
} catch(IOException e) {
e.printStackTrace();
}
}
public void start() {
for(int i=0; i < threadArr.length; i++) {
threadArr[i] = new Thread(this);
threadArr[i].start();
}
}
public void run() {
while(true) {
try {
System.out.println(getTime()+ "가 연결요청을 기다립니다.");
Socket socket = serverSocket.accept();
System.out.println(getTime()+ socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");
// 소켓의 출력스트림을 얻는다.
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
// 원격 소켓(remote socket)에 데이터를 보낸다.
dos.writeUTF("[Notice] Test Message1 from Server.");
System.out.println(getTime()+"데이터를 전송했습니다.");
// 스트림과 소켓을 닫아준다.
dos.close();
socket.close();
} catch (SocketTimeoutException e) {
System.out.println("지정된 시간동안 접속요청이 없어서 서버를 종료합니다.");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
} // while
} // run
// 현재시간을 문자열로 반환하는 함수
static String getTime() {
String name = Thread.currentThread().getName();
SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
return f.format(new Date()) + name ;
}
} // class
16.6.4 채팅 프로그램 예제
- Server
public class TcpIpServer5 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(7778);
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();
}
}
}
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) {}
}
}
}
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) {}
}
}
}
- Client
public class TcpIpClient5 {
public static void main(String[] args) {
try {
String serverIp = "127.0.0.1";
Socket socket = new Socket(serverIp, 7778);
System.out.println("서버에 연결되었습니다.");
Sender sender = new Sender(socket);
Receiver receiver = new Receiver(socket);
sender.start();
receiver.start();
} catch (ConnectException e) {
e.getStackTrace();
} catch (IOException e) {
e.getStackTrace();
} catch (Exception e) {
e.getStackTrace();
}
}
}
16.6.5 멀티 채팅 프로그램 예제
- Server
public class TcpIpMultichatServer {
HashMap<String, DataOutputStream> clients;
public TcpIpMultichatServer() {
clients = new HashMap<String, DataOutputStream>();
Collections.synchronizedMap(clients);
}
public void start() {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(7778);
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();
}
}
void sendToAll(String msg) {
Iterator<String> it = clients.keySet().iterator();
while (it.hasNext()) {
try {
DataOutputStream out = (DataOutputStream)clients.get(it.next());
out.writeUTF(msg);
} catch (IOException e) {}
}
}
public static void main(String[] args) {
new TcpIpMultichatServer().start();
}
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) {
} finally {
sendToAll("#"+name+"님이 나가셨습니다.");
clients.remove(name);
System.out.println("["+socket.getInetAddress()+":"+socket.getPort()+"]에서 접속을 종료하였습니다.");
System.out.println("현재 서버접속자 수는 "+clients.size()+"입니다.");
}
}
}
}
- Client
public class TcpIpMultichatClient {
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, 7778);
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 e) {
e.getStackTrace();
} catch (Exception e) {
e.getStackTrace();
}
}
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) {}
}
}
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) {}
}
}
}
}
'자바의 정석 정리' 카테고리의 다른 글
자바의 정석 - 11.1 컬렉션 프레임웍 (0) | 2022.09.05 |
---|---|
자바의 정석 - 16.7 UDP 소켓 프로그래밍 (0) | 2022.08.31 |
자바의 정석 - 16.5 소켓 프로그래밍 (0) | 2022.08.31 |
자바의 정석 - 16.4 URLConnection (0) | 2022.08.31 |
자바의 정석 - 16.3 URL (0) | 2022.08.31 |