21 Mart 2018 Çarşamba

ServerSocket Sınıfı - TCP Sunucu Soketi

Giriş
Bu sınıf TCP sunucu soketi içindir. TCP istemci soketi için Socket sınıfı kullanılır. UDP istemci ve sunucu soketi için DatagramSocket sınıfı kullanılır. Şu satırı dahil ederiz.
import java.net.ServerSocket;
Not: Server Socket İçin Boş Port Bulma yazısına bakabilirsiniz

constructor - ServerSocketFactory
Direkt constructor metodları kullanmak yerine ServerSocketFactory kullanılabilir.

constructor - port
Örnek
Bind işlemini gerçekleştirir. Şöyle yaparız.
ServerSocket serverSocket = new ServerSocket(4_444);
constructor - port + backlog + bind address
İstersek port numarası + backlog + bind address verebiliriz.
Örnek
Şöyle yaparız. Sadece 127.0.0.1 adresi dinleniyor.
ServerSocket serverSocket = 
  new ServerSocket(9_902, 1, InetAddress.getByName("localhost"));
constructor - ServerSocketChannel
Şöyle yaparız.
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false); 
ServerSocket  serverSocket = serverSocketChannel.socket();
accept metodu
Örnek
Şöyle yaparız.
Socket socket = serverSocket.accept();
Örnek
Zaman aşımı ile kullanmak istersek şöyle yaparız.
try {
  serverSocket.setSoTimeout(1_000);
  Socket client = serverSocket.accept();
  ...
} catch (SocketTimeoutException ste) {
  ...
} catch (IOException io) {
...
}
bind metodu
Eğer default constructor ile nesnemizi yarattıysak bu metodu çağırmamız gerekir.
InetSocketAddress isa = new InetSocketAddress("localhost", 7_777);
serverSocket.bind(isa); 
Şöyle yaparız.
InetSocketAddress isa = new InetSocketAddress(7_777);
serverSocket.bind(isa); 
close metodu
Şöyle yaparız.
serverSocket.close();
getLocalPort metodu
Örnek
Şöyle yaparız
InetSocketAddress randomSocketAddressFirst = new InetSocketAddress(0);

try (ServerSocket ssOne = new ServerSocket()) {
  System.out.println("randomSocketAddress port before any binding : " + 
    randomSocketAddressFirst.getPort());
  ssOne.bind(randomSocketAddressFirst);
  System.out.println("local port after first binding :" + ssOne.getLocalPort());
}

try (ServerSocket ssTwo = new ServerSocket()) {
  ssTwo.bind(randomSocketAddressFirst);
  System.out.println("local port after second binding :" + ssTwo.getLocalPort());
  System.out.println("randomSocketAddress port after all bindings : " + 
    randomSocketAddressFirst.getPort());
}
// Output
randomSocketAddress port before any binding : 0
local port after first binding : 65110
local port after second binding : 65111
randomSocketAddress port after all bindings : 0
getLocalSocketAddress metodu
Örnek
Şöyle yaparız. 
// localAddress is 0.0.0.0/0.0.0.0:52898
InetSocketAddress localAddress = (InetSocketAddress) serverSocket.getLocalSocketAddress();
setPerformancePreferences metodu - connectionTime + latency + bandwidth
İmzası şöyle
public void setPerformancePreferences(int connectionTime,
                                      int latency,
                                      int bandwidth)
Java 6'ya kadar bu metodun için boş.
public void setPerformancePreferences(int connectionTime,
                                      int latency,
                                      int bandwidth)
{
/* Not implemented yet */
}
Şöyle yaparız.
serverSocket.setPerformancePreferences(1000, 20_000, 2_000);
setReuseAddress metodu
Bu metod iki tane server socket'in aynı anda aynı portu dinleyebilmesini sağlamaz! Açıklaması şöyle. Sadece kapanmakta olan bir socketin tamamen kapanmasını beklemeden yeni bir server socket'in bu portu kullanabilmesini sağlar.
This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy, but with another state, you will still get an address already in use error. It is useful if your server has been shut down, and then restarted right away while sockets are still active on its port. You should be aware that if any unexpected data comes in, it may confuse your server, but while this is possible, it is not likely.
Örnek
Şöyle yaparız.
serverSocket.setReuseAddress(true);
setSoTimeout metodu
Açıklaması şöyle
There is no mechanism to set a write timeout on a java.net.Socket. There is a Socket.setSoTimeout() method, but it affects accept() and read() calls ... and not write() calls.
Şöyle yaparız.
serverSocket.setSoTimeout(10_000);
Diğer
Sunucu socket açarken BindException'a dikkat etmek gerekir. Şöyle yaparız.
import java.io.IOException;
import java.net.BindException;

import java.net.ServerSocket;

ServerSocket socket;

try {
  socket = new ServerSocket(...);
  ...
}
catch (BindException e) {
  System.err.println("Already running.");
  ...
}
catch (IOException e) {
  System.err.println("Unexpected error.");
  ...
}
Thread Kullanan Çok Basit Bir Sunucu Kodu
Şöyle yaparız.
ServerSocket serverSocket = new ServerSocket(8082);
Thread serverThread = new Thread(() -> {
  while(true) {
    try {
      Socket connection = serverSocket.accept();

      try (
        BufferedReader reader = new BufferedReader(
                       new InputStreamReader(connection.getInputStream()));
        Writer serverWriter = new BufferedWriter(
                       new OutputStreamWriter(connection.getOutputStream()));
      ) {
        serverWriter.write("hello, " + serverReader.readLine() + "\n");
        serverWriter.flush();
        }
      } catch (IOException e) {
        e.printStackTrace();
      } catch (Throwable t) {
        t.printStackTrace();
        throw t;
      }
    }
  });
serverThread.setDaemon(true);
serverThread.start();
Executor Kullanan Çok Basit Bir Sunucu Kodu
Şöyle yaparız.
clientProcessingPool = Executors.newFixedThreadPool(50);

while (!clientProcessingPool.isShutdown()) {
  try {
    Socket socket = serverSocket.accept();
    clientProcessingPool.submit(new MyRunnable(socket, this));
  } catch (SocketTimeoutException e) {
    e.printStackTrace();
  } catch (Exception e) {
    e.printStackTrace();
  }
}
serverSocket.close();





Hiç yorum yok:

Yorum Gönder