자바 소켓 프로그래밍 : 튜토리얼

이 튜토리얼은 Java I / O의 기본 기능을 보여주는 간단한 클라이언트-서버 예제로 시작하여 Java 소켓 프로그래밍에 대한 소개입니다. Java 1.4에 도입 된 java.io 비 차단 I / O ( java.nio) API 인 원본 패키지와 NIO 를 모두 소개합니다  . 마지막으로 NIO.2에서 Java 7부터 구현 된 Java 네트워킹을 보여주는 예제를 볼 수 있습니다.

소켓 프로그래밍은 서로 통신하는 두 시스템으로 귀결됩니다. 일반적으로 네트워크 통신은 TCP (Transport Control Protocol)와 UDP (User Datagram Protocol)의 두 가지 형태로 제공됩니다. TCP와 UDP는 서로 다른 용도로 사용되며 둘 다 고유 한 제약 조건이 있습니다.

  • TCP는 클라이언트가 서버와 통신 할 두 시스템에 연결할 수 있도록하는 비교적 간단하고 안정적인 프로토콜입니다. TCP에서 각 엔티티는 통신 페이로드가 수신되었음을 알고 있습니다.
  • UDP는 비 연결 프로토콜 이며 미디어 스트리밍과 같이 모든 패킷이 대상에 도착할 필요가없는 시나리오에 적합합니다.

TCP와 UDP의 차이점을 이해하려면 즐겨 찾는 웹 사이트에서 비디오를 스트리밍하고 프레임이 삭제되면 어떤 일이 발생할지 고려하십시오. 클라이언트가 누락 된 프레임을 수신하기 위해 영화의 속도를 늦추기를 원합니까, 아니면 비디오가 계속 재생되는 것을 원합니까? 비디오 스트리밍 프로토콜은 일반적으로 UDP를 활용합니다. TCP는 전달을 보장하기 때문에 HTTP, FTP, SMTP, POP3 등에 대해 선택하는 프로토콜입니다.

이 튜토리얼에서는 Java로 소켓 프로그래밍을 소개합니다. 원래 Java I / O 프레임 워크의 기능을 보여주는 일련의 클라이언트-서버 예제를 제시 한 다음 점차 NIO.2에 도입 된 기능을 사용하도록 진행합니다.

구식 Java 소켓

NIO 이전의 구현에서 Java TCP 클라이언트 소켓 코드는 java.net.Socket클래스에 의해 처리됩니다 . 다음 코드는 서버에 대한 연결을 엽니 다.

 소켓 소켓 = new Socket (server, port); 

socket인스턴스가 서버에 연결 되면 서버에 대한 입력 및 출력 스트림을 얻을 수 있습니다. 입력 스트림은 서버에서 데이터를 읽는 데 사용되는 반면 출력 스트림은 서버에 데이터를 쓰는 데 사용됩니다. 입력 및 출력 스트림을 얻기 위해 다음 메소드를 실행할 수 있습니다.

InputStream 입력 = socket.getInputStream (); OutputStream 출력 = socket.getOutputStream ();

이러한 스트림은 파일에서 읽고 쓰는 데 사용하는 것과 동일한 스트림이기 때문에 사용 사례에 가장 적합한 형식으로 변환 할 수 있습니다. 예를 들어, 우리는 포장 할 수 OutputStream로모그래퍼 PrintStream그래서 우리는 같은 방법으로 쉽게 쓰기 텍스트를 할 수 있습니다 println(). 또 다른 예를 들어, 우리는 포장 할 수 InputStreamA를을 BufferedReader을 통해, InputStreamReader같은 방법으로 쉽게 읽기 텍스트 순서 readLine().

다운로드 "Java의 소켓 프로그래밍 : 튜토리얼"의 소스 코드 소스 코드를 다운로드하십시오. JavaWorld를 위해 Steven Haines가 작성했습니다.

자바 소켓 클라이언트 예

HTTP 서버에 대해 HTTP GET을 실행하는 간단한 예제를 살펴 보겠습니다. HTTP는 예제에서 허용하는 것보다 더 정교하지만 가장 간단한 경우를 처리하기 위해 클라이언트 코드를 작성할 수 있습니다. 서버에서 리소스를 요청하면 서버가 응답을 반환하고 스트림을 닫습니다. 이 경우 다음 단계가 필요합니다.

  1. 포트 80에서 수신하는 웹 서버에 대한 소켓을 만듭니다.
  2. 를 얻 PrintStream서버 및 요청 전송 GET PATH HTTP/1.0, PATH서버에서 요청 된 리소스입니다. 예를 들어, 웹 사이트의 루트를 열려면 경로는 /.
  3. 를 취득 InputStream, 서버에 그것을 포장 BufferedReader하고 응답을 한 줄 한 줄을 읽어 보시기 바랍니다.

목록 1은이 예제의 소스 코드를 보여줍니다.

목록 1. SimpleSocketClientExample.java

com.geekcap.javaworld.simplesocketclient 패키지; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class SimpleSocketClientExample {public static void main (String [] args) {if (args.length <2) {System.out.println ( "Usage : SimpleSocketClientExample"); System.exit (0); } 문자열 서버 = args [0]; 문자열 경로 = args [1]; System.out.println ( "URL 내용로드 :"+ server); try {// 서버에 연결합니다. Socket socket = new Socket (server, 80); // 서버에서 읽고 쓸 입력 및 출력 스트림을 만듭니다. PrintStream out = new PrintStream (socket.getOutputStream ()); BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ())); // GET HTTP / 1의 HTTP 프로토콜을 따릅니다.0 뒤에 빈 줄이옵니다 out.println ( "GET"+ path + "HTTP / 1.0"); out.println (); // 문서 읽기가 끝날 때까지 서버에서 데이터를 읽습니다. String line = in.readLine (); while (line! = null) {System.out.println (line); 라인 = in.readLine (); } // 스트림을 닫습니다. in.close (); out.close (); socket.close (); } catch (예외 e) {e.printStackTrace (); }}}

목록 1은 연결할 서버 (포트 80에서 서버에 연결한다고 가정)와 검색 할 리소스의 두 가지 명령 줄 인수를 허용합니다. 그것은 생성 Socket하는 서버를 가리키고 명시 적으로 지정 포트를 80. 그런 다음 다음 명령을 실행합니다.

경로 가져 오기 HTTP / 1.0 

예를 들면 :

GET / HTTP / 1.0 

방금 무슨 일이 있었나요?

와 같은 웹 서버에서 웹 페이지를 검색 할 때 www.google.comHTTP 클라이언트는 DNS 서버를 사용하여 서버의 주소를 찾습니다. 우선 최상위 도메인 서버에 .NET 용 com신뢰할 수있는 도메인 이름 서버가있는 도메인을 요청합니다 www.google.com. 그런 다음 도메인 이름 서버에 .NET의 IP 주소 (또는 주소)를 요청 www.google.com합니다. 다음으로 포트 80에서 해당 서버에 대한 소켓을 엽니 다. (또는 다른 포트를 정의하려는 경우 콜론 뒤에 포트 번호를 추가하여 수행 할 수 있습니다 :8080. 예 : .) 마지막으로 HTTP 클라이언트는 다음을 실행합니다. 지정된 HTTP 메소드와 같은 GET, POST, PUT, DELETE, HEAD, 또는 OPTI/ONS. 각 메서드에는 고유 한 구문이 있습니다. 위의 코드 조각에서 볼 수 있듯이이 GET메서드에는 경로가 필요합니다.HTTP/version number그리고 빈 줄. HTTP 헤더를 추가하려면 새 줄을 입력하기 전에 추가 할 수 있습니다.

Listing 1에서 우리는 텍스트 기반 명령을 더 쉽게 실행할 수 OutputStream있도록를 가져 와서로 래핑했습니다 PrintStream. 우리의 코드는 얻은 InputStream에 그 포장, InputStreamReader로 변환하는 Reader, 다음에 있음을 감싸 BufferedReader. 우리는 사용 PrintStream우리의 실행 GET방법을 다음을 사용 BufferedReader우리가 수신 될 때까지 응답 한 줄 한 줄을 읽어 null소켓이 폐쇄되었다는 것을 나타내는 응답을.

이제이 클래스를 실행하고 다음 인수를 전달합니다.

java com.geekcap.javaworld.simplesocketclient.SimpleSocketClientExample www.javaworld.com / 

다음과 유사한 출력이 표시되어야합니다.

Loading contents of URL: www.javaworld.com HTTP/1.1 200 OK Date: Sun, 21 Sep 2014 22:20:13 GMT Server: Apache X-Gas_TTL: 10 Cache-Control: max-age=10 X-GasHost: gas2.usw X-Cooking-With: Gasoline-Local X-Gasoline-Age: 8 Content-Length: 168 Last-Modified: Tue, 24 Jan 2012 00:09:09 GMT Etag: "60001b-a8-4b73af4bf3340" Content-Type: text/html Vary: Accept-Encoding Connection: close     Gasoline Test Page

Success

This output shows a test page on JavaWorld's website. It replied back that it speaks HTTP version 1.1 and the response is 200 OK.

Java socket server example

We've covered the client side and fortunately the communication aspect of the server side is just as easy. From a simplistic perspective, the process is as follows:

  1. Create a ServerSocket, specifying a port to listen on.
  2. Invoke the ServerSocket's accept() method to listen on the configured port for a client connection.
  3. When a client connects to the server, the accept() method returns a Socket through which the server can communicate with the client. This is the same Socket class that we used for our client, so the process is the same: obtain an InputStream to read from the client and an OutputStream write to the client.
  4. If you server needs to be scalable, you will want to pass the Socket to another thread to process so that your server can continue listening for additional connections.
  5. Call the ServerSocket's accept() method again to listen for another connection.

As you'll soon see, NIO's handling of this scenario would be a bit different. For now, though, we can directly create a ServerSocket by passing it a port to listen on (more about ServerSocketFactorys in the next section):

 ServerSocket serverSocket = new ServerSocket( port ); 

And now we can accept incoming connections via the accept() method:

 Socket socket = serverSocket.accept(); // Handle the connection ... 

Multithreaded programming with Java sockets

Listing 2, below, puts all of the server code so far together into a slightly more robust example that uses threads to handle multiple requests. The server shown is an echo server, meaning that it echoes back any message it receives.

While the example in Listing 2 isn't complicated it does anticipate some of what's coming up in the next section on NIO. Pay special attention to the amount of threading code we have to write in order to build a server that can handle multiple simultaneous requests.

Listing 2. SimpleSocketServer.java

package com.geekcap.javaworld.simplesocketclient; import java.io.BufferedReader; import java.io.I/OException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SimpleSocketServer extends Thread { private ServerSocket serverSocket; private int port; private boolean running = false; public SimpleSocketServer( int port ) { this.port = port; } public void startServer() { try { serverSocket = new ServerSocket( port ); this.start(); } catch (I/OException e) { e.printStackTrace(); } } public void stopServer() { running = false; this.interrupt(); } @Override public void run() { running = true; while( running ) { try { System.out.println( "Listening for a connection" ); // Call accept() to receive the next connection Socket socket = serverSocket.accept(); // Pass the socket to the RequestHandler thread for processing RequestHandler requestHandler = new RequestHandler( socket ); requestHandler.start(); } catch (I/OException e) { e.printStackTrace(); } } } public static void main( String[] args ) { if( args.length == 0 ) { System.out.println( "Usage: SimpleSocketServer " ); System.exit( 0 ); } int port = Integer.parseInt( args[ 0 ] ); System.out.println( "Start server on port: " + port ); SimpleSocketServer server = new SimpleSocketServer( port ); server.startServer(); // Automatically shutdown in 1 minute try { Thread.sleep( 60000 ); } catch( Exception e ) { e.printStackTrace(); } server.stopServer(); } } class RequestHandler extends Thread { private Socket socket; RequestHandler( Socket socket ) { this.socket = socket; } @Override public void run() { try { System.out.println( "Received a connection" ); // Get input and output streams BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) ); PrintWriter out = new PrintWriter( socket.getOutputStream() ); // Write out our header to the client out.println( "Echo Server 1.0" ); out.flush(); // Echo lines back to the client until the client closes the connection or we receive an empty line String line = in.readLine(); while( line != null && line.length() > 0 ) { out.println( "Echo: " + line ); out.flush(); line = in.readLine(); } // Close our connection in.close(); out.close(); socket.close(); System.out.println( "Connection closed" ); } catch( Exception e ) { e.printStackTrace(); } } }