수색…


통사론

  • 새로운 소켓 ( "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();

소켓 닫기 및 예외 처리

위의 예는 읽기 쉽도록 몇 가지 사항을 생략했습니다.

  1. 파일 및 기타 외부 리소스와 마찬가지로, 작업이 완료되면 OS에 알려야합니다. 소켓이 끝나면 socket.close() 를 호출하여 제대로 닫습니다.

  2. 소켓은 다양한 외부 요소에 의존하는 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 에의 도입은, 오브젝트 명 내의 임의의 단어 TrustKey 치환하는 것을 제외하면, 동일하게 기능합니다. 또한 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 블록을 비워 두지 마십시오!
  • 오류가 발생하면 원격 파일이 있는지 확인하십시오.
  • 이것은 차단 작업이며 대용량 파일로 오랜 시간이 걸릴 수 있습니다.


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow