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アーキテクチャーと各スレッドの予想される負荷に応じて、クライアント数が1000以下の場合)限り正常に動作します。
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を終了したら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)
ソケットの例 - 単純なソケットを使ってWebページを読む
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
で始まり、HTMLヘッダーの残りが続き、その後にHTML形式の生のWebページが続きます。
早すぎるEOF例外を防ぐには、 readFully()
メソッドが重要であることに注意してください。 Webページの最後の行に改行がないと、行の終わりを知らせることができます。そうすれば、 readLine()
は手作業で読むか、 Apacheのユーティリティメソッドを使用する必要があります。io IOtils
この例は、ソケットを使用して既存のリソースに接続する簡単なデモを意味していますが、実際のWebページにアクセスする方法ではありません。 Javaを使用してWebページにアクセスする必要がある場合は、 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の一種です。通常のデータグラムとは異なり、マルチキャスティングは個々のクライアントを個別に処理するのではなく、1つの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 */ }
ノート
- キャッチブロックを空にしないでください!
- エラーが発生した場合は、リモートファイルが存在するかどうかを確認してください
- これはブロック操作であり、大きなファイルでは時間がかかる