네트워크 프로그래밍
package tcp;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Ex01_server {
public static void main(String[] args) throws Exception {
// 서버소켓 클래스 객체 생성
// 예외처리 필요, 12345 는 Port 번호
ServerSocket server = new ServerSocket(12345);
System.out.println("접속을 기다립니다!!!");
// accept() - 클라이언트가 연결될때까지 기다리는 메소드
// 즉, 클라이언트가 연결되어야 "클라이언트 연결되었습니다!!!" 문구가 실행됨
// server.accept() 를 소켓 객체로 담아 접속 클라이언트의 정보를
// sock 이라는 이름으로 저장한다
Socket sock = server.accept();
System.out.println("클라이언트 연결되었습니다!!!");
// InputStream 이라는 객체 입력 클래스 객체를
// 소켓을 통해 사용하겠다.
InputStream is = sock.getInputStream();
// 데이터 수신
int readData = is.read();
System.out.println("수신 데이터 : " + readData);
is.close(); sock.close(); server.close();
}
}
Server
package tcp;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex01_client {
public static void main(String[] args) throws Exception {
// 현재 학원 PC 아이피 : 192.168.42.118
// Server socket 설정 포트번호 : 12345
// 클라이언트는 소켓 클래스 객체로 서버에 연결 요청
// 객체 생성 시 아이피 정보, 포트 정보가 들어감
Socket sock = new Socket("192.168.42.118", 12345);
System.out.println("클라이언트 실행!!!");
// OutputStream ㅇ;라는 데이터 출력 클래스 객체를
// sock 이라는 소켓을 통해 사용하겠다
OutputStream os = sock.getOutputStream();
Scanner input = new Scanner(System.in);
System.out.print("수 입력 : ");
int data = input.nextInt();
// 데이터 전송
os.write(data);
os.close(); sock.close();
}
}
Client
기본 스트림이 전송할 수 있는 값은 1 byte 단위이다.
1 byte = 0 ~ 255
만약 256 을 전송하였다면 0 으로 server 가 받으며, 257 을 전송하였다면 1 로 server 가 받는다.
그러므로 보조 스트림을 사용하여 문자열, 객체 등을 전송할 수 있게 해줘야 한다.
보조스트림을 사용하여 문자열을 수, 발신 하기
package tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Ex02_server {
public static void main(String[] args) throws Exception {
// 서버 소켓 생성, 포트번호 10000
ServerSocket server = new ServerSocket(10000);
System.out.println("접속 대기....");
// Socket 클래스로 클라이언트의 정보를 담아둠
Socket sock = server.accept();
// 현재 서버 접속자의 정보 출력
System.out.println(sock.getInetAddress());
InputStream in = sock.getInputStream();
DataInputStream dis = new DataInputStream(in);
// 수신한 데이터(문자열) 저장
String readData = dis.readUTF();
System.out.println("수신 데이터 : " + readData);
// sock 에는 이미 클라이언트에 대한 정보가 들어있으므로
// sock 을 이용하여 클라이언트로 데이터를 전송할 수 있음
OutputStream os = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
Scanner input = new Scanner(System.in);
System.out.print("클라이언트로 전송할 데이터 입력 : ");
String sendData = input.nextLine();
dos.writeUTF(sendData);
dis.close(); in.close();
dos.close(); os.close();
sock.close(); server.close();
}
}
Server
package tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex02_client {
public static void main(String[] args) throws Exception {
// 로컬 루프백 주소인 127.0.0.1 로 지정, 포트 10000 으로 접속 시도
Socket sock = new Socket("127.0.0.1", 10000);
OutputStream out = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
Scanner input = new Scanner(System.in);
System.out.print("전송할 문자열 입력 : ");
String data = input.nextLine();
dos.writeUTF(data);
InputStream is = sock.getInputStream();
DataInputStream dis = new DataInputStream(is);
String readData = dis.readUTF();
System.out.println("수신 데이터 : " + readData);
dos.close(); out.close();
dis.close(); is.close();
sock.close();
}
}
Client
클라이언트 두 곳과 연결
package tcp;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Ex03_server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(12345);
System.out.println("접속을 기다립니다...");
// 접속 순서에 따라 sock01, sock02 로 클라이언트에 대한 정보를 저장한다
Socket sock01 = server.accept();
Socket sock02 = server.accept();
System.out.println("접속 되었습니다.");
// sock01 로부터 날아오는 데이터를 저장한다.
// sock02 에서 날아온 데이터는 따로 저장되지 않는다...!!
InputStream in = sock01.getInputStream();
DataInputStream dis = new DataInputStream(in);
String readData = dis.readUTF();
System.out.println("수신 데이터 : " + readData);
dis.close(); in.close(); sock01.close(); sock02.close();
server.close();
}
}
Server
package tcp;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex03_client01 {
public static void main(String[] args) throws Exception {
Scanner input = new Scanner(System.in);
Socket sock = new Socket("127.0.0.1", 12345);
OutputStream out = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
System.out.print("송신 데이터 입력 : ");
String data = input.nextLine();
dos.writeUTF(data);
dos.close(); out.close(); sock.close(); input.close();
}
}
Client01
package tcp;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex03_client02 {
public static void main(String[] args) throws Exception {
Scanner input = new Scanner(System.in);
Socket sock = new Socket("127.0.0.1", 12345);
OutputStream out = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
System.out.print("송신 데이터 입력 : ");
String data = input.nextLine();
dos.writeUTF(data);
dos.close(); out.close(); sock.close(); input.close();
}
}
Client02
객체를 직렬화하여 전송하기
직렬화 - 객체를 byte 형식으로 변환
객체는 byte 형식으로 직렬화하여 보내지 않으면 오류가 발생하기 때문에 꼭 직렬화 를 하여 전송해야 한다
package tcp;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Ex04_server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(12345);
System.out.println("접속 대기");
Socket sock = server.accept();
System.out.println("접속 되었음");
InputStream in = sock.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
Ex04_DTO dto = (Ex04_DTO)ois.readObject();
System.out.println("수신 name : " + dto.getName());
System.out.println("수신 addr : " + dto.getAddr());
ois.close(); in.close(); sock.close();
server.close();
}
}
Server
package tcp;
import java.io.Serializable;
public class Ex04_DTO implements Serializable{
// Serializable 상속하여 꼭 직렬화 해주기!
private String name, addr;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
DTO
package tcp;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex04_client {
public static void main(String[] args) throws Exception {
Socket sock = new Socket("127.0.0.1", 12345);
Scanner sc = new Scanner(System.in);
OutputStream out = sock.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
Ex04_DTO dto = new Ex04_DTO();
System.out.print("이름 입력 : ");
dto.setName(sc.next());
System.out.print("주소 입력 : ");
dto.setAddr(sc.next());
oos.writeObject(dto);
oos.close(); out.close(); sock.close();
}
}
Client
쓰레드를 사용하여 다중 client 에게 데이터 전송받기
Thread 를 사용하지 않으면 클라이언트에게 응답을 받을때 하나씩 받거나 응답이 오지않으면 무한대기에 빠지기 때문에 쓰레드를 사용하여 다중의 데이터를 받아 처리한다
다자간 채팅 서버
기억할 것 : 소켓으로 클라이언트가 접속하면 서버는 ArrayList 를 사용하여 클라이언트의 Socket 정보를 배열로 저장한뒤 수신 받은 데이터를 변수로 다시 선언하여 OutputStream 을 사용하여 ArrayList 안에 담긴 Socket 정보로 다시 전송하는 형태
Server 의 Thread : 다중 클라이언트의 데이터를 전송받고 다시 연결된 클라이언트들에게 데이터를 전송하기 위해 사용
Client 의 Thread : 발신은 Thread 를 사용하지 않고 클라이언트에서 진행되며, Thread 를 사용하여 실시간으로 들어오는 데이터를 수신
package tcp;
import java.net.ServerSocket;
import java.net.Socket;
public class Ex06_server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(12345);
while(true) {
System.out.println("접속을 기다립니다...");
Socket s = server.accept();
System.out.println(s.getInetAddress() + "님 접속");
// 쓰레드 객체를 생성
new Ex06_serverThread(s);
}
}
}
Server
package tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
public class Ex06_serverThread extends Thread {
// arr 변수를 static 으로 선언하여 모든 쓰레드가 공유하여 사용할 수
// 있게끔 생성한다
public static ArrayList<Socket> arr;
static {
arr = new ArrayList<>();
}
private Socket s;
public Ex06_serverThread(Socket s) {
// ArrayList 에 사용자들의 정보(소켓)를 저장
arr.add(s);
this.s = s;
start(); // start 메소드 실행 시 run 메소드 자동 실행
}
@Override
public void run() {
try {
// InputStream in = arr.get( arr.size()-1 ).getInputStream();
// 현재 접속한 사용자로부터 데이터를 수신
InputStream in = s.getInputStream();
DataInputStream dis = new DataInputStream(in);
while(true) {
// 수신한 데이터를 변수에 저장
// readUTF 메소드는 입력값이 들어올때까지 대기하다가 입력 값이
// 들어오면 그때 메소드가 동작한다!!!!
// 그러므로 빈 값을 클라이언트에게 무한으로 던지지 않는다
String msg = dis.readUTF();
for(Socket ss : arr) {
// 배열로 저장된 현재 연결된 클라이언트들에게 수신 데이터를
// 다시 전송
OutputStream out = ss.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
dos.writeUTF(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server Thread
package tcp;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex06_client01 {
public static void main(String[] args) throws Exception {
// 소켓 생성
Socket sock = new Socket("127.0.0.1", 12345);
OutputStream out = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
Scanner sc = new Scanner(System.in);
String msg = null;
// 수신되는 데이터는 쓰레드 객체를 생성하여 수신
Ex06_clientThread rcv = new Ex06_clientThread(sock);
while(true) {
// 클라이언트에서 전송하는 데이터는 while 문으로 계속 입력받음
System.out.print("전송 데이터 입력 : ");
msg = sc.nextLine();
dos.writeUTF(msg);
}
}
}
Client01
package tcp;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Ex06_client02 {
public static void main(String[] args) throws Exception {
// 소켓 생성
Socket sock = new Socket("127.0.0.1", 12345);
OutputStream out = sock.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
Scanner sc = new Scanner(System.in);
String msg = null;
// 수신되는 데이터는 쓰레드 객체를 생성하여 수신
Ex06_clientThread rcv = new Ex06_clientThread(sock);
while(true) {
// 클라이언트에서 전송하는 데이터는 while 문으로 계속 입력받음
System.out.print("전송 데이터 입력 : ");
msg = sc.nextLine();
dos.writeUTF(msg);
}
}
}
Client02
package tcp;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class Ex06_clientThread extends Thread {
Socket sock;
public Ex06_clientThread(Socket sock) {
// 클라이언트가 객체 생성할때 들고온 Socket 정보를 sock 으로 저장
// 서로 다른 클라이언트가 접근하면 클라이언트 1개 당
// 쓰레드 객체가 1개씩 신규로 생성된다
this.sock = sock;
start(); // 쓰레드에서 start 메소드가 실행되면 run 메소드도 자동으로 실행된다
}
@Override
public void run() {
try {
// Socket 으로 연결된 서버에서 전달 받는 정보를 쓰레드를 사용하여
// 메세지를 발신하면서도 독립적으로 계속 수신받게끔 설정
InputStream in = sock.getInputStream();
DataInputStream dis = new DataInputStream(in);
while(true) {
String data = dis.readUTF();
System.out.println("수신 데이터 : " + data);
}
}catch (Exception e) {
}
}
}
Client Thread
- 프로그램 작동 순서 -
Server 에서 서버 소켓 생성 후 클라이언트가 접속하는 것을 대기
> 클라이언트 1 이 서버 소켓에 접속
> 서버쓰레드가 공유하는 arr 배열에 클라이언트 1의 소켓 정보를 저장
> 서버 쓰레드 1 과 클라이언트 1 쓰레드가 동시에 생성 및 작동
> 클라이언트 2 가 서버 소켓에 접속
> 서버쓰레드가 공유하는 arr 배열에 클라이언트 2의 소켓 정보를 저장
> 서버 쓰레드 2 와 클라이언트 2 쓰레드가 동시에 생성 및 작동
> 클라이언트 1에서 데이터를 전송
> 서버 쓰레드 1 에서 전송받은 데이터를 arr 배열에 존재하는 사용자정보(Socket)에 모두 전송
> 클라이언트 쓰레드 1, 2 는 서버쓰레드 1 에서 전송받은 데이터를 출력
> 클라이언트 2에서 데이터를 전송
> 서버 쓰레드 2 에서 전송받은 데이터를 arr 배열에 존재하는 사용자정보(Socket)에 모두 전송
> 클라이언트 쓰레드 1, 2 는 서버쓰레드 2 에서 전송받은 데이터를 출력
'국비지원_핀테크' 카테고리의 다른 글
18일차_ [DB] 정렬, inner join, group by (1) | 2024.02.28 |
---|---|
17일차_ [DB] Oracle DB 설치, sqldeveloper 설치 및 DB 생성, 기본 문법 (1) | 2024.02.27 |
15일차_ [java] 미니 프로젝트 ( 파일 입출력, 스트림 클래스 활용 ) (0) | 2024.02.23 |
15일차_ [java] 직렬화 ( Serializable ) (0) | 2024.02.23 |
15일차_ [DB] DB 다운로드 (0) | 2024.02.23 |