Java Language
네트워킹
수색…
통사론
- 새로운 소켓 ( "localhost", 1234); // 주소 "localhost"및 포트 1234에있는 서버에 연결합니다.
- 새로운 SocketServer ( "localhost", 1234); // 주소 localhost 및 포트 1234에서 새로운 소켓을 수신 할 수있는 소켓 서버를 만듭니다.
- socketServer.accept (); // 클라이언트와 통신하는 데 사용할 수있는 새 Socket 객체를 승인합니다.
소켓을 사용하는 기본 클라이언트 및 서버 통신
서버 : 시작하고 들어오는 연결을 기다립니다.
//Open a listening "ServerSocket" on port 1234.
ServerSocket serverSocket = new ServerSocket(1234);
while (true) {
// Wait for a client connection.
// Once a client connected, we get a "Socket" object
// that can be used to send and receive messages to/from the newly
// connected client
Socket clientSocket = serverSocket.accept();
// Here we'll add the code to handle one specific client.
}
서버 : 클라이언트 처리
별도의 스레드에서 각 클라이언트를 처리하므로 여러 클라이언트가 동시에 서버와 상호 작용할 수 있습니다. 이 기술은 클라이언트 수가 적 으면 잘 작동합니다 (OS 아키텍처 및 각 스레드의 예상로드에 따라 클라이언트가 1,000 명 미만).
new Thread(() -> {
// Get the socket's InputStream, to read bytes from the socket
InputStream in = clientSocket.getInputStream();
// wrap the InputStream in a reader so you can read a String instead of bytes
BufferedReader reader = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8));
// Read text from the socket and print line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}).start();
클라이언트 : 서버에 연결하고 메시지 보내기
// 127.0.0.1 is the address of the server (this is the localhost address; i.e.
// the address of our own machine)
// 1234 is the port that the server will be listening on
Socket socket = new Socket("127.0.0.1", 1234);
// Write a string into the socket, and flush the buffer
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
소켓 닫기 및 예외 처리
위의 예는 읽기 쉽도록 몇 가지 사항을 생략했습니다.
파일 및 기타 외부 리소스와 마찬가지로, 작업이 완료되면 OS에 알려야합니다. 소켓이 끝나면
socket.close()
를 호출하여 제대로 닫습니다.소켓은 다양한 외부 요소에 의존하는 I / O (입력 / 출력) 연산을 처리합니다. 예를 들어 상대방이 갑자기 연결을 끊으면 어떻게됩니까? 네트워크 오류가 발생하면 어떻게해야합니까? 이러한 것들은 우리가 통제 할 수없는 것입니다. 이것이 많은 소켓 조작이 예외, 특히
IOException
발생시키는 이유입니다.
그러므로 클라이언트를위한보다 완전한 코드는 다음과 같다.
// "try-with-resources" will close the socket once we leave its scope
try (Socket socket = new Socket("127.0.0.1", 1234)) {
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
} catch (IOException e) {
//Handle the error
}
기본 서버 및 클라이언트 - 전체 예제
섬기는 사람:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String args[]) {
try (ServerSocket serverSocket = new ServerSocket(1234)) {
while (true) {
// Wait for a client connection.
Socket clientSocket = serverSocket.accept();
// Create and start a thread to handle the new client
new Thread(() -> {
try {
// Get the socket's InputStream, to read bytes
// from the socket
InputStream in = clientSocket.getInputStream();
// wrap the InputStream in a reader so you can
// read a String instead of bytes
BufferedReader reader = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8));
// Read from the socket and print line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch (IOException e) {
e.printStackTrace();
} finally {
// This finally block ensures the socket is closed.
// A try-with-resources block cannot be used because
// the socket is passed into a thread, so it isn't
// created and closed in the same block
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
고객:
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Client {
public static void main(String args[]) {
try (Socket socket = new Socket("127.0.0.1", 1234)) {
// We'll reach this code once we've connected to the server
// Write a string into the socket, and flush the buffer
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
} catch (IOException e) {
// Exception should be handled.
e.printStackTrace();
}
}
}
InputStream로부터의 TrustStore 및 KeyStore의로드
public class TrustLoader {
public static void main(String args[]) {
try {
//Gets the inputstream of a a trust store file under ssl/rpgrenadesClient.jks
//This path refers to the ssl folder in the jar file, in a jar file in the same directory
//as this jar file, or a different directory in the same directory as the jar file
InputStream stream = TrustLoader.class.getResourceAsStream("/ssl/rpgrenadesClient.jks");
//Both trustStores and keyStores are represented by the KeyStore object
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//The password for the trustStore
char[] trustStorePassword = "password".toCharArray();
//This loads the trust store into the object
trustStore.load(stream, trustStorePassword);
//This is defining the SSLContext so the trust store will be used
//Getting default SSLContext to edit.
SSLContext context = SSLContext.getInstance("SSL");
//TrustMangers hold trust stores, more than one can be added
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//Adds the truststore to the factory
factory.init(trustStore);
//This is passed to the SSLContext init method
TrustManager[] managers = factory.getTrustManagers();
context.init(null, managers, null);
//Sets our new SSLContext to be used.
SSLContext.setDefault(context);
} catch (KeyStoreException | IOException | NoSuchAlgorithmException
| CertificateException | KeyManagementException ex) {
//Handle error
ex.printStackTrace();
}
}
}
KeyStore 에의 도입은, 오브젝트 명 내의 임의의 단어 Trust
를 Key
치환하는 것을 제외하면, 동일하게 기능합니다. 또한 KeyManager[]
배열은 SSLContext.init
의 첫 번째 인수로 전달되어야합니다. SSLContext.init(keyMangers, trustMangers, null)
소켓 예제 - 간단한 소켓을 사용하여 웹 페이지 읽기
import java.io.*;
import java.net.Socket;
public class Main {
public static void main(String[] args) throws IOException {//We don't handle Exceptions in this example
//Open a socket to stackoverflow.com, port 80
Socket socket = new Socket("stackoverflow.com",80);
//Prepare input, output stream before sending request
OutputStream outStream = socket.getOutputStream();
InputStream inStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
PrintWriter writer = new PrintWriter(new BufferedOutputStream(outStream));
//Send a basic HTTP header
writer.print("GET / HTTP/1.1\nHost:stackoverflow.com\n\n");
writer.flush();
//Read the response
System.out.println(readFully(reader));
//Close the socket
socket.close();
}
private static String readFully(Reader in) {
StringBuilder sb = new StringBuilder();
int BUFFER_SIZE=1024;
char[] buffer = new char[BUFFER_SIZE]; // or some other size,
int charsRead = 0;
while ( (charsRead = rd.read(buffer, 0, BUFFER_SIZE)) != -1) {
sb.append(buffer, 0, charsRead);
}
}
}
정상적인 HTTP 응답을 나타내는 HTTP/1.1 200 OK
시작하는 응답을 얻고 나머지 HTTP 헤더와 HTML 형식의 원시 웹 페이지 순으로 응답을 받아야합니다.
조기 EOF 예외를 방지하려면 readFully()
메서드가 중요합니다. 웹 페이지의 마지막 줄에 줄 바꿈이 없다면 readLine()
이 불평 할 것이므로 직접 읽거나 Apache의 유틸리티 메소드를 사용해야합니다. commons-IOUtils
이 예제는 소켓을 사용하여 기존 자원에 연결하는 간단한 데모로서 의미가 있지만 웹 페이지에 액세스하는 실제 방법은 아닙니다. Java를 사용하여 웹 페이지에 액세스해야하는 경우 Apache HTTP 클라이언트 또는 Google HTTP 클라이언트 와 같은 기존 HTTP 클라이언트 라이브러리를 사용하는 것이 가장 좋습니다
UDP (데이터 그램)를 이용한 기본 클라이언트 / 서버 통신
Client.java
import java.io.*;
import java.net.*;
public class Client{
public static void main(String [] args) throws IOException{
DatagramSocket clientSocket = new DatagramSocket();
InetAddress address = InetAddress.getByName(args[0]);
String ex = "Hello, World!";
byte[] buf = ex.getBytes();
DatagramPacket packet = new DatagramPacket(buf,buf.length, address, 4160);
clientSocket.send(packet);
}
}
이 경우 인수 ( args[0]
)를 통해 서버의 주소를 전달합니다. 우리가 사용하는 포트는 4160입니다.
Server.java
import java.io.*;
import java.net.*;
public class Server{
public static void main(String [] args) throws IOException{
DatagramSocket serverSocket = new DatagramSocket(4160);
byte[] rbuf = new byte[256];
DatagramPacket packet = new DatagramPacket(rbuf, rbuf.length);
serverSocket.receive(packet);
String response = new String(packet.getData());
System.out.println("Response: " + response);
}
}
서버 측에서 우리가 보낸 메시지와 동일한 포트 (4160)에 DatagramSocket을 선언하고 응답을 기다린다.
멀티 캐스팅
멀티 캐스팅은 Datagram Socket의 한 유형입니다. 일반 데이터 그램과 달리 멀티 캐스팅은 각 클라이언트를 개별적으로 처리하지 않고 하나의 IP 주소로 보내고 구독 한 모든 클라이언트는 메시지를 받게됩니다.
서버 측 예제 코드 :
public class Server {
private DatagramSocket serverSocket;
private String ip;
private int port;
public Server(String ip, int port) throws SocketException, IOException{
this.ip = ip;
this.port = port;
// socket used to send
serverSocket = new DatagramSocket();
}
public void send() throws IOException{
// make datagram packet
byte[] message = ("Multicasting...").getBytes();
DatagramPacket packet = new DatagramPacket(message, message.length,
InetAddress.getByName(ip), port);
// send packet
serverSocket.send(packet);
}
public void close(){
serverSocket.close();
}
}
클라이언트 측 예제 코드 :
public class Client {
private MulticastSocket socket;
public Client(String ip, int port) throws IOException {
// important that this is a multicast socket
socket = new MulticastSocket(port);
// join by ip
socket.joinGroup(InetAddress.getByName(ip));
}
public void printMessage() throws IOException{
// make datagram packet to recieve
byte[] message = new byte[256];
DatagramPacket packet = new DatagramPacket(message, message.length);
// recieve the packet
socket.receive(packet);
System.out.println(new String(packet.getData()));
}
public void close(){
socket.close();
}
}
서버 실행 코드 :
public static void main(String[] args) {
try {
final String ip = args[0];
final int port = Integer.parseInt(args[1]);
Server server = new Server(ip, port);
server.send();
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
클라이언트 실행 코드 :
public static void main(String[] args) {
try {
final String ip = args[0];
final int port = Integer.parseInt(args[1]);
Client client = new Client(ip, port);
client.printMessage();
client.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
먼저 클라이언트 실행 : 패킷 수신을 시작하려면 먼저 클라이언트가 IP에 가입해야합니다. 서버를 시작하고 send()
메소드를 호출 한 다음 클라이언트 ( printMessage()
호출)를 작성하십시오. 메시지를 보낸 후에 연결된 클라이언트 때문에 아무 일도 발생하지 않습니다.
일시적으로 SSL 확인 사용 중지 (테스트 목적)
때로 개발 환경이나 테스트 환경에서 SSL 인증서 체인이 아직 설정되지 않았을 수 있습니다.
개발 및 테스트를 계속 진행하려면 "모두 신뢰하는"신뢰 관리자를 설치하여 SSL 검증을 프로그래밍 방식으로 해제 할 수 있습니다.
try {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
채널을 사용하여 파일 다운로드
파일이 이미 존재하면 덮어 씁니다!
String fileName = "file.zip"; // name of the file
String urlToGetFrom = "http://www.mywebsite.com/"; // URL to get it from
String pathToSaveTo = "C:\\Users\\user\\"; // where to put it
//If the file already exists, it will be overwritten!
//Opening OutputStream to the destination file
try (ReadableByteChannel rbc =
Channels.newChannel(new URL(urlToGetFrom + fileName).openStream()) ) {
try ( FileChannel channel =
new FileOutputStream(pathToSaveTo + fileName).getChannel(); ) {
channel.transferFrom(rbc, 0, Long.MAX_VALUE);
}
catch (FileNotFoundException e) { /* Output directory not found */ }
catch (IOException e) { /* File IO error */ }
}
catch (MalformedURLException e) { /* URL is malformed */ }
catch (IOException e) { /* IO error connecting to website */ }
노트
- catch 블록을 비워 두지 마십시오!
- 오류가 발생하면 원격 파일이 있는지 확인하십시오.
- 이것은 차단 작업이며 대용량 파일로 오랜 시간이 걸릴 수 있습니다.