ネットワーク通信2

7603 ワード

サーバー


サーバは、2つのスロットを受信する責任を負います->サーバソケット:accept(複数のユーザー接続)
conSocket:accept後の新しいオブジェクトの戻り(実際の責任)-->クライアントに関連付けられたソケット
接続者が1人増えるたびにconsocketは増加し続けます.
package ex07.network.fileServer02;

import java.io.IOException;
import java.io.*;
import java.net.*;


//클라이언트가 요청하는 파일을 전송하는 역할의 서버 
public class FileServer {
	public static void main(String[] args) {
		// 1) 접속을 받아주는 역할의 소켓 객체를 생성 
		try {
			ServerSocket serverSocket = new ServerSocket(9000);
			System.out.println("파일 클라이언트 접속 대기...");
			
			// 2)VIPS 안내매니저가 담당 직원을 연결시켜줌 
			// conSocket이 클라이언트와의 통신을 하는 역할을 한다
			// conSocket 내부에는 송/수신 스트림이 생성되어 있다 -->이걸통하면 클라이언트와 통신할 수 있음 
			Socket conSocket = serverSocket.accept();
			System.out.println("파일 클라이언트 접속 완료! ");
			
			//3) 통신을 위해 stream 객체를 얻는다
			// 3-1) 수신 stream
			InputStream in = conSocket.getInputStream();
			DataInputStream dIn = new DataInputStream(in);
			
			// 3-2) 송신 stream
			OutputStream out = conSocket.getOutputStream();
			DataOutputStream dOut = new DataOutputStream(out);
			
			
			//4) 파일을 수신한다
			// 4-1) 파일명을 수신한다 
			String fileName = dIn.readUTF();
			System.out.println("사용자 요청 파일 " + fileName);
			
			
			// 4-2) 파일을 연결한다 
			FileInputStream fIn = new FileInputStream(fileName);
			
			// 4-3) 파일 데이터를 송신한다  
			while(true) {
				// int는 4byte지만 실제로는 1byte만 읽어서 채운다 
				int data = fIn.read();
				if(data == -1) {		//더이상 읽을 것이 없다 
					System.out.println("--- 모두 전송했습니다 ---");
					break;
				}else {	//읽었으면 클라이언트한테 전송한다 
					dOut.write(data);
				}
						
			}
			fIn.close(); dOut.close(); out.close();
			dIn.close(); in.close(); serverSocket.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}

クライアント

package ex07.network.fileServer02;

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class FileClient {
	public static void main(String[] args) {
		try {
			// 1) 서버에 접속할 소켓 객체를 생성(서버IP, Port)
			//    객체가 생성되면 서버와의 스트림이 연결된다
			Socket clientSocket = new Socket("127.0.0.1", 9000);
			
			// 2) 키보드 입력 객체를 생성
			Scanner sc = new Scanner(System.in);
			
			// 3) 송/수신 stream을 얻는다
			//   3-1) 수신 stream
			InputStream in = clientSocket.getInputStream();
			DataInputStream dIn = new DataInputStream(in);
			
			//   3-2) 송신 stream
			OutputStream out = clientSocket.getOutputStream();
			DataOutputStream dOut = new DataOutputStream(out);
			
			// 4) 서버로부터 다운로드할 파일 명 입력
			System.out.print("다운로드 파일명 입력 >> ");
			String fileName = sc.nextLine();
			
			// 5) 파일명을 서버로 전송
			dOut.writeUTF(fileName);
			System.out.println("서버에 파일명을 보냈습니다~");
			
			// 6) 다운로드 파일을 저장할 파일을 연결
			String dFileName = "new_" + fileName;
			FileOutputStream outFile = new FileOutputStream(dFileName);
			
			// 7) 서버로부터 파일 다운로드
			System.out.println("서버로부터 파일을 다운로드 시작합니다!");
			while(true) {
				int data = dIn.read();
				if(data==-1) {
					System.out.println("다운로드 완료! ");
					break;
				}else {
					outFile.write(data);
				}
			}
			
			System.out.println("클라이언트 종료 ");
			outFile.close(); dOut.close(); out.close();
			dIn.close(); in.close(); clientSocket.close();
			
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

マルチスレッド


誰かが返事をしなければ、他の人は止まります.
コンセントごとにスレッドが付いています

DB接続やネットワーク接続では例外処理がよく使われます.
内部問題ではなく予測しにくい外部問題

サーバー

package ex07.network.multiThreadServer04;

import java.io.*;
import java.net.*;

/*
[서버]
1) 동기 서버 : 현재 우리가 만드는 서버는 
            "멀티스레드 동기 에코 서버"
2) 비동기 서버
*/
/*
[멀티스레드 동기 서버]
1) 장점 : 동시에 여러 클라이언트에 대응할 수 있다
2) 단점 : 접속자가 많아지면 스레드가 많아진다
         스레드는 "Context Switching"이 많이 발생한다
         그러므로 반응속도가 느려진다
     (Apache Server의 특징)
*/
public class MultiThreadEchoServer {
	final static int PORT = 9000;

	public static void main(String[] args) {
		try {
			// 1) accept()처리를 위한 "서버 소켓 객체"를 생성한다
			// 클라이언트가 접속시 연결 처리 후
			// 새로운 통신소켓과 연결해주는 역할(담당자 역할 소켓 부여)
			ServerSocket serverSocket = new ServerSocket(PORT);

//			2) 클라이언트가 접속 요청을 할 때마다 계속 accept()처리를 
//               해야 한다 - main thread의 역할
			while (true) {
				System.out.println("클라이언트 접속 대기...");
//				clientSocket이 클라이언트와 통신하는 소켓
				Socket clientSocket = serverSocket.accept();
				// 접속 클라이언트당 1개의 스레드를 배치
				// 고객과의 송수신은 스레드 니가 알아서 처리해라 
				EchoThread echoThread = new EchoThread(clientSocket);
				echoThread.start();
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class EchoThread extends Thread {
	private Socket socket;

	EchoThread(Socket socket) {
		this.socket = socket;
	}

	// JVM에 의해 할당된 스레드는 run()을 실행하게 된다
	// run()에서는 클라이언트의 메시지를 수신 -> 표시 -> Echo 전송
	// 을 반복한다
	@Override
	public void run() {

		try {
			// 1) 어떤 클라이언트가 접속했나?
			InetAddress inetAddr = socket.getInetAddress();
			System.out.println(inetAddr.getHostAddress() + "로부터 접속했습니다~");

			// 2) 송/수신 stream 객체얻기
			// 2-1) 송신 stream
			OutputStream out = socket.getOutputStream();
			OutputStreamWriter outW = new OutputStreamWriter(out);
			PrintWriter pw = new PrintWriter(outW);

			// 2-2) 수신 stream
			InputStream in = socket.getInputStream();
			InputStreamReader inR = new InputStreamReader(in);
			BufferedReader br = new BufferedReader(inR);
			
			// 3) Echo 기능 수행 : 수신 -> 표시 -> 송신
			while(true) {
				//3-1) 수신 
				String line = br.readLine();
				if(line==null) {
					System.out.println("클라이언트 접속 단절!");
					break;
				}else {	// 정상적으로 메시지가 담겨있다면
					//3-2) 화면에 표시
					System.out.println(inetAddr.getHostAddress() + 
								" 클라이언트로부터 수신 : " + line);
					//3-3) 클라이언트에 echo 송신
					pw.println(line);
					pw.flush();
				}
			}
			System.out.println(inetAddr.getHostAddress() +
							" 클라이언트 접속 종료!!!");
			pw.close(); outW.close(); out.close();
			br.close(); inR.close(); in.close();
			socket.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

クライアント

package ex07.network.multiThreadServer04;

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class EchoLoopClient {
	public static void main(String[] args) throws UnknownHostException, IOException {

		Socket clientSocket = new Socket("106.240.16.169", 9000);

		InputStreamReader inK = new InputStreamReader(System.in);
		BufferedReader keyboard = new BufferedReader(inK);
		
		OutputStream out = clientSocket.getOutputStream();
		OutputStreamWriter outW = new OutputStreamWriter(out);
		PrintWriter pw = new PrintWriter(outW);
		
//		수신
		InputStream in = clientSocket.getInputStream();
		InputStreamReader inR = new InputStreamReader(in);
		BufferedReader br = new BufferedReader(inR);

		while(true) {
			System.out.print("입력 >> ");
			String line = keyboard.readLine();
			if(line == null) {
				System.out.println("서버 종료");
				break;
			}
			else if(line.equals("quit")) {
				System.out.println("클라이언트 Quit");
				break;
			}
			System.out.println("서버로 전송 : " + line);
			pw.println(line);
			pw.flush();
			
			// 서버가 echo하는 것을 받아서 출력
			String echo = br.readLine();
			System.out.println("서버로부터 수신 : " + echo);
		}
		
		// 5) 열려있는 객체들을 모두 닫는다
		pw.close();
		outW.close();
		out.close();
		br.close();
		inR.close();
		in.close();
		clientSocket.close();
	}
}