์๋ฐ ์์ผ ํต์
์์ผ์ด๋?
์์ผ(Socket)์ด๋ ๋คํธ์ํฌ ํต์ ์ ์ํ ์๋ํฌ์ธํธ์
๋๋ค.
์์ผ(Socket)์ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๊ธฐ ์ํ ํต์ ์ ๋์ (endpoint)์
๋๋ค.
์์ผ์ IP ์ฃผ์์ ํฌํธ ๋ฒํธ์ ์กฐํฉ์ผ๋ก ์๋ณ๋๋ฉฐ, ๋ ํ๋ก๊ทธ๋จ ๊ฐ์ ์๋ฐฉํฅ ํต์ ์ฑ๋์ ์ ๊ณตํฉ๋๋ค. TCP ์์ผ์ ๊ฒฝ์ฐ ์ฐ๊ฒฐ ์งํฅ์ ์ด๋ฉฐ, 3-way handshake๋ฅผ ํตํด ์ฐ๊ฒฐ์ ์๋ฆฝํ๊ณ ๋ฐ์ดํฐ์ ์์์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค. ์์ผ์ OSI 7๊ณ์ธต ๋ชจ๋ธ์์ ์ ์ก ๊ณ์ธต๊ณผ ์์ฉ ๊ณ์ธต ์ฌ์ด์ ์ธํฐํ์ด์ค ์ญํ ์ ํ๋ฉฐ, ๊ฐ๋ฐ์๊ฐ ๋คํธ์ํฌ ํ๋ก๊ทธ๋๋ฐ์ ํ ์ ์๋๋ก ์ถ์ํ๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค. Java์์๋ Socket ํด๋์ค(ํด๋ผ์ด์ธํธ)์ ServerSocket ํด๋์ค(์๋ฒ)๋ฅผ ํตํด ์์ผ ํ๋ก๊ทธ๋๋ฐ์ ๊ตฌํํ ์ ์์ต๋๋ค.
์ฃผ์ ๊ฐ๋
โข
IP ์ฃผ์: ๋คํธ์ํฌ ์์์ ์ปดํจํฐ๋ฅผ ์๋ณํ๋ ์ฃผ์
โข
ํฌํธ ๋ฒํธ: ํ๋์ ์ปดํจํฐ ๋ด์์ ์คํ๋๋ ์ฌ๋ฌ ํ๋ก๊ทธ๋จ์ ๊ตฌ๋ถํ๋ ๋ฒํธ (0~65535)
โข
ํ๋กํ ์ฝ: ํต์ ๊ท์ฝ (TCP, UDP ๋ฑ)
TCP vs UDP
๊ตฌ๋ถ | TCP | UDP |
์ฐ๊ฒฐ ๋ฐฉ์ | ์ฐ๊ฒฐ ์งํฅ | ๋น์ฐ๊ฒฐ ์งํฅ |
์ ๋ขฐ์ฑ | ๋์ (๋ฐ์ดํฐ ์์ ๋ณด์ฅ) | ๋ฎ์ (์์ ๋ณด์ฅ ์ ํจ) |
์๋ | ์๋์ ์ผ๋ก ๋๋ฆผ | ๋น ๋ฆ |
์ฌ์ฉ ์ | ์น, ์ด๋ฉ์ผ, ํ์ผ ์ ์ก | ์คํธ๋ฆฌ๋ฐ, ์จ๋ผ์ธ ๊ฒ์ |
TCP ์์ผ ํต์ ๊ตฌ์กฐ
์๋ฒ-ํด๋ผ์ด์ธํธ ๋ชจ๋ธ
์ญํ | ์ค๋ช
|
์๋ฒ | ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ ์์ฒญ์ ๋๊ธฐํ๊ณ ์๋ฝ |
ํด๋ผ์ด์ธํธ | ์๋ฒ์ ์ฐ๊ฒฐ์ ์์ฒญํ๊ณ ๋ฐ์ดํฐ ์ก์์ |
ํต์ ํ๋ฆ
1.
์๋ฒ๊ฐ ํน์ ํฌํธ์์ ๋๊ธฐ (ServerSocket)
2.
ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์ฐ๊ฒฐ ์์ฒญ (Socket)
3.
์๋ฒ๊ฐ ์ฐ๊ฒฐ ์๋ฝ
4.
๋ฐ์ดํฐ ์ก์์ (InputStream, OutputStream)
5.
์ฐ๊ฒฐ ์ข
๋ฃ
Windows ๋ฐฉํ๋ฒฝ ํฌํธ ๊ฐ๋ฐฉ ๋ฐฉ๋ฒ
Java ์์ผ ํต์ ์ ์ํด์๋ ์๋ฒ๊ฐ ์ฌ์ฉํ๋ ํฌํธ๋ฅผ ๋ฐฉํ๋ฒฝ์์ ํ์ฉํด์ผ ํฉ๋๋ค.
์ธ๋ฐ์ด๋ ๊ท์น ์ถ๊ฐํ๊ธฐ
1.
Windows ๋ฐฉํ๋ฒฝ ์ค์ ์ด๊ธฐ
โข
์์ ๋ฉ๋ด์์ "Windows Defender ๋ฐฉํ๋ฒฝ" ๊ฒ์
โข
"๊ณ ๊ธ ์ค์ " ํด๋ฆญ
2.
์ ์ธ๋ฐ์ด๋ ๊ท์น ๋ง๋ค๊ธฐ
โข
์ผ์ชฝ ๋ฉ๋ด์์ "์ธ๋ฐ์ด๋ ๊ท์น" ์ ํ
โข
์ค๋ฅธ์ชฝ "์์
" ํจ๋์์ "์ ๊ท์น..." ํด๋ฆญ
3.
๊ท์น ์ ํ ์ ํ
โข
"ํฌํธ" ์ ํ
โข
"๋ค์" ํด๋ฆญ
4.
ํ๋กํ ์ฝ ๋ฐ ํฌํธ ์ง์
โข
"TCP" ์ ํ (Java ์์ผ์ ์ผ๋ฐ์ ์ผ๋ก TCP ์ฌ์ฉ)
โข
"ํน์ ๋ก์ปฌ ํฌํธ" ์ ํ
โข
ํฌํธ ๋ฒํธ ์
๋ ฅ (์: 9999)
โข
"๋ค์" ํด๋ฆญ
5.
์์
์ ํ
โข
"์ฐ๊ฒฐ ํ์ฉ" ์ ํ
โข
"๋ค์" ํด๋ฆญ
6.
ํ๋กํ ์ ํ
โข
๊ท์น์ ์ ์ฉํ ๋คํธ์ํฌ ํ๋กํ ์ ํ (๋๋ฉ์ธ, ๊ฐ์ธ, ๊ณต์ฉ)
โข
์ผ๋ฐ์ ์ผ๋ก "๊ฐ์ธ" ์ฒดํฌ
โข
"๋ค์" ํด๋ฆญ
7.
์ด๋ฆ ๋ฐ ์ค๋ช
โข
๊ท์น ์ด๋ฆ ์
๋ ฅ (์: "Java Socket Server Port 9999")
โข
์ ํ์ ์ผ๋ก ์ค๋ช
์ถ๊ฐ
โข
"๋ง์นจ" ํด๋ฆญ
๋ช ๋ น ํ๋กฌํํธ๋ก ํฌํธ ๊ฐ๋ฐฉ
๊ด๋ฆฌ์ ๊ถํ์ผ๋ก ๋ช
๋ น ํ๋กฌํํธ๋ฅผ ์ด์ด ๋ค์ ๋ช
๋ น์ด๋ฅผ ์คํํ ์๋ ์์ต๋๋ค:
netsh advfirewall firewall add rule name="Java Socket Port 9999" dir=in action=allow protocol=TCP localport=9999
PowerShell
๋ณต์ฌ
ํฌํธ ๊ฐ๋ฐฉ ํ์ธ
ํฌํธ๊ฐ ์ ๋๋ก ์ด๋ ธ๋์ง ํ์ธํ๋ ค๋ฉด:
netstat -an | findstr :9999
PowerShell
๋ณต์ฌ
โข
ํ
์คํธ ๋ชฉ์ ์ผ๋ก๋ง ํฌํธ๋ฅผ ๊ฐ๋ฐฉํ์ธ์
โข
๊ณต์ฉ ๋คํธ์ํฌ์์๋ ์ฃผ์๊ฐ ํ์ํฉ๋๋ค
โข
์ฌ์ฉํ์ง ์๋ ํฌํธ๋ ๋ซ์๋๋ ๊ฒ์ด ์์ ํฉ๋๋ค
์๋ฒ ๊ตฌํ
ServerSocket ํด๋์ค
ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ ์์ฒญ์ ์์ ํ๋ ์ญํ ์ ํฉ๋๋ค.
import java.io.*;
import java.net.*;
public class SimpleServer {
public static void main(String[] args) {
int port = 9999;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("์๋ฒ๊ฐ ํฌํธ " + port + "์์ ๋๊ธฐ ์ค...");
// ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ๋๊ธฐ
Socket clientSocket = serverSocket.accept();
System.out.println("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ: " + clientSocket.getInetAddress());
// ์
์ถ๋ ฅ ์คํธ๋ฆผ ์์ฑ
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())
);
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true
);
// ๋ฉ์์ง ์์ ๋ฐ ์๋ต
String message = in.readLine();
System.out.println("๋ฐ์ ๋ฉ์์ง: " + message);
out.println("์๋ฒ ์๋ต: " + message);
// ์ฐ๊ฒฐ ์ข
๋ฃ
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
๋ณต์ฌ
์ฃผ์ ๋ฉ์๋
โข
ServerSocket(int port): ์ง์ ๋ ํฌํธ๋ก ์๋ฒ ์์ผ ์์ฑ
โข
accept(): ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์์ฒญ ๋๊ธฐ ๋ฐ ์๋ฝ (๋ธ๋กํน ๋ฉ์๋)
โข
close(): ์๋ฒ ์์ผ ๋ซ๊ธฐ
ํด๋ผ์ด์ธํธ ๊ตฌํ
Socket ํด๋์ค
์๋ฒ์ ์ฐ๊ฒฐํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ก์์ ํ๋ ์ญํ ์ ํฉ๋๋ค.
import java.io.*;
import java.net.*;
public class SimpleClient {
public static void main(String[] args) {
String serverAddress = "localhost";
int port = 9999;
try (Socket socket = new Socket(serverAddress, port)) {
System.out.println("์๋ฒ์ ์ฐ๊ฒฐ๋จ");
// ์
์ถ๋ ฅ ์คํธ๋ฆผ ์์ฑ
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true
);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
// ๋ฉ์์ง ์ ์ก
out.println("์๋
ํ์ธ์, ์๋ฒ!");
// ์๋ต ์์
String response = in.readLine();
System.out.println("์๋ฒ ์๋ต: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
๋ณต์ฌ
์ฃผ์ ๋ฉ์๋
โข
Socket(String host, int port): ์ง์ ๋ ํธ์คํธ์ ํฌํธ๋ก ์ฐ๊ฒฐ
โข
getInputStream(): ์
๋ ฅ ์คํธ๋ฆผ ๋ฐํ
โข
getOutputStream(): ์ถ๋ ฅ ์คํธ๋ฆผ ๋ฐํ
โข
close(): ์์ผ ์ฐ๊ฒฐ ๋ซ๊ธฐ
๋ค์ค ํด๋ผ์ด์ธํธ ์ฒ๋ฆฌ
์ฌ๋ฌ ํด๋ผ์ด์ธํธ๋ฅผ ๋์์ ์ฒ๋ฆฌํ๋ ค๋ฉด ์ค๋ ๋๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
import java.io.*;
import java.net.*;
public class MultiThreadServer {
public static void main(String[] args) {
int port = 9999;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("๋ค์ค ํด๋ผ์ด์ธํธ ์๋ฒ ์์...");
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("์ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ: " + clientSocket.getInetAddress());
// ๊ฐ ํด๋ผ์ด์ธํธ๋ฅผ ๋ณ๋ ์ค๋ ๋์์ ์ฒ๋ฆฌ
ClientHandler handler = new ClientHandler(clientSocket);
Thread thread = new Thread(handler);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ClientHandler implements Runnable {
private Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true
)
) {
String message;
while ((message = in.readLine()) != null) {
System.out.println("๋ฐ์ ๋ฉ์์ง: " + message);
out.println("์์ฝ: " + message);
if (message.equalsIgnoreCase("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Java
๋ณต์ฌ
์ค์ ์์ : ์ฑํ ํ๋ก๊ทธ๋จ
์ฑํ ์๋ฒ
package socket;
import java.io.*;
import java.net.*;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class ChatServer {
// ๋ชจ๋ ํด๋ผ์ด์ธํธ๋ค์ ์ถ๋ ฅ ์คํธ๋ฆผ์ ์ ์ฅํ ๋ฆฌ์คํธ (Thread safe)
private static List<PrintWriter> clientWriterList = new CopyOnWriteArrayList<>();
public static void main(String[] args) {
int port = 9999;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("์๋ฒ ๋๊ธฐ ์ค: " + port);
// ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๋ฅผ ๊ณ์ ๋ฐ๊ธฐ ์ํด ๋ฌดํ ๋ฃจํ
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ: " + clientSocket.getInetAddress());
// ๊ฐ ํด๋ผ์ด์ธํธ๋ฅผ ๋ณ๋ ์ค๋ ๋๋ก ์ฒ๋ฆฌ
new Thread(new ClientHandler(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
} // main() ๋
// ๋ธ๋ก๋์บ์คํธ : ๋ชจ๋ ํด๋์ด์ธํธ์ ๋ฉ์์ง ์ ์ก
public static void broadcast(String message, PrintWriter sender) {
for (PrintWriter writer : clientWriterList) {
if( writer != sender ) {
writer.println(message);
}
}
}
// ํด๋ผ์ด์ธํธ์์ ํต์ ์ ๋ด๋นํ๋ ํด๋์ค
static class ClientHandler implements Runnable {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
private String clientName;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
out = new PrintWriter(socket.getOutputStream(), true);
// ๊ฐ๋ณ ํด๋ผ์ด์ธํธ์ ์ถ๋ ฅ์คํธ๋ฆผ์ ๋ฆฌ์คํธ์ ์ถ๊ฐ
clientWriterList.add(out);
out.println("์ด๋ฆ : ");
clientName = in.readLine();
System.out.println("* " + clientName + "๋ ์
์ฅ!");
// ์
์ฅ
broadcast("* " + clientName + "๋ ์
์ฅ!", out);
// ๊ณ์ ์ฑํ
String message;
while ((message = in.readLine()) != null) {
System.out.println("[" + clientName + "] ๋ฉ์์ง: " + message);
// ๋ธ๋ก๋์บ์คํธ
broadcast("[" + clientName + "] ๋ฉ์์ง: " + message, out);
if (message.equalsIgnoreCase("exit")) {
System.out.println("[" + socket.getInetAddress() + "] ์ฐ๊ฒฐ ์ข
๋ฃ ์์ฒญ");
break;
}
}
} catch (IOException e) {
System.out.println("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ค๋ฅ: " + e.getMessage());
} finally {
try {
if(out != null) clientWriterList.remove(out);
if( clientName != null ) {
broadcast(clientName + "๋์ด ํด์ฅํ์ต๋๋ค.", out);
}
socket.close();
System.out.println("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ข
๋ฃ๋จ: " + socket.getInetAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Java
๋ณต์ฌ
์ฑํ ํด๋ผ์ด์ธํธ
package socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class SimpleClient {
public static void main(String[] args) {
String serverAddress = "localhost";
int port = 9999;
try (
Socket socket = new Socket(serverAddress, port);
Scanner sc = new Scanner(System.in);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
) {
System.out.println("์๋ฒ์ ์ฐ๊ฒฐ๋จ");
// ์๋ฒ์์ ์ค๋ ๋ฉ์์ง ์
๋ ฅ
Thread receiver = new Thread(() -> {
try {
String response;
while( (response = in.readLine() ) != null ) {
System.out.println(response);
}
} catch (Exception e) {
System.out.println("์๋ฒ ์ฐ๊ฒฐ ์ข
๋ฃ");
}
});
receiver.start();
// ์๋ฒ๋ก ์ถ๋ ฅ
while(true) {
String input = sc.nextLine();
out.println(input); // ์๋ฒ๋ก ์ฑํ
๋ณด๋
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java
๋ณต์ฌ
์ฃผ์์ฌํญ ๋ฐ Best Practices
์์ธ ์ฒ๋ฆฌ
โข
IOException: ๋คํธ์ํฌ ์ค๋ฅ ์ ๋ฐ์
โข
SocketException: ์์ผ ๊ด๋ จ ์ค๋ฅ
โข
ํญ์ try-with-resources ์ฌ์ฉ: ์์ ์๋ ํด์
ํ์์์ ์ค์
// ์ฐ๊ฒฐ ํ์์์ (๋ฐ๋ฆฌ์ด)
socket.connect(new InetSocketAddress(host, port), 5000);
// ์ฝ๊ธฐ ํ์์์
socket.setSoTimeout(10000);
Java
๋ณต์ฌ
๋ฒํผ๋ง
โข
ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ ์ก์ ์ํด BufferedReader์ BufferedWriter ์ฌ์ฉ
โข
PrintWriter์ autoFlush ์ต์
ํ์ฉ
์ค๋ ๋ ์์ ์ฑ
โข
๊ณต์ ์์ ์ ๊ทผ ์ synchronized ์ฌ์ฉ
โข
์ค๋ ๋ ํ(ExecutorService) ์ฌ์ฉ ๊ณ ๋ ค





