Eğitim Portalı/Java/Ağ Programlama (Networking) Temelleri
Java01-java/30-networking-temelleri

Ağ Programlama (Networking) Temelleri

Bugün yazdığımız uygulamaların neredeyse hiçbiri yalnız çalışmaz: bir mobil uygulama sunucuya istek atar, bir web sitesi veritabanına bağlanır, mikroservisler birbirleriyle konuşur. Bütün bunların altında ağ programla…

Ağ Programlama (Networking) Temelleri

Bugün yazdığımız uygulamaların neredeyse hiçbiri yalnız çalışmaz: bir mobil uygulama sunucuya istek atar, bir web sitesi veritabanına bağlanır, mikroservisler birbirleriyle konuşur. Bütün bunların altında ağ programlama vardır. İyi haber şu ki Java, ağ iletişimini standart kütüphanesi (java.net) ile baştan destekler; üstelik bunu dosya okur gibi, akışlarla (stream) yapmana izin verir. Bu bölümde ağın temel kavramlarını ve Java'nın bunları nasıl modellediğini, internet gerektirmeden, kendi makinende çalışan örneklerle öğreneceğiz.

Ağın temel kavramları

Bir ağ iletişimini anlamak için birkaç kavramı netleştirelim:

  • IP adresi: Ağdaki her makinenin kimliği. IPv4 (192.168.1.5) veya IPv6 (2001:db8::1).
  • Port: Bir makinedeki belirli bir servisin "kapı numarası" (0–65535). Web sunucusu 80/443, veritabanı 5432/3306 gibi. Bir IP + port = bir uç nokta (endpoint).
  • localhost / loopback (127.0.0.1, ::1): "Bu makinenin kendisi". Ağ kartına bile gitmeden, makinenin kendi içinde iletişim. Test için idealdir (ve internet gerektirmez).
  • DNS: İnsan-okunur adları (example.com) IP adreslerine çeviren "telefon rehberi".
  • İstemci / Sunucu (client/server): Sunucu bir portu dinler ve bağlantı bekler; istemci o porta bağlanır. İstek-cevap bu kanal üzerinden akar.

Adresleri tanımak: InetAddress

Java'da bir makineyi/IP'yi InetAddress temsil eder. Ad↔IP çözümleme, loopback erişimi ve ulaşılabilirlik testi sağlar:

InetAddress loopback = InetAddress.getLoopbackAddress(); // 127.0.0.1
InetAddress localhost = InetAddress.getByName("localhost");
InetAddress benim = InetAddress.getLocalHost();          // bu makine
loopback.isReachable(1000);                               // ulaşılabilir mi?

Örnek 1 (./Ornek1.java) bunları çalıştırır (loopback ve yerel makineyle; internet gerekmez) ve IPv4/IPv6 ayrımını gösterir.

İki taşıma protokolü: TCP ve UDP

Veriyi ağ üzerinden taşımanın iki temel yolu vardır ve seçim işin doğasına bağlıdır:

TCP (Transmission Control Protocol)

Bağlantı tabanlı ve güvenilir: önce bir bağlantı kurulur (handshake), sonra veri sırayla, kayıpsız ve doğrulanarak akar. Java'da:

  • Sunucu: ServerSocket bir portu dinler, accept() ile bağlantı bekler (bloklar).
  • İstemci: Socket ile sunucuya bağlanır.
  • İki taraf da giriş/çıkış akışlarıyla (getInputStream/getOutputStream) konuşur — tıpkı dosya okur/yazar gibi.
ServerSocket sunucu = new ServerSocket(port);
Socket istemci = sunucu.accept();      // bağlantı bekle
// ... in/out akışlarıyla konuş ...
Socket soket = new Socket("localhost", port); // istemci bağlanır

Örnek 2 (./Ornek2.java) tek bir JVM'de bir TCP echo sunucusu (gelen satırı geri yansıtan) ve ona bağlanan bir istemci kurar. HTTP, FTP, veritabanı bağlantıları... hepsi TCP üzerindedir.

UDP (User Datagram Protocol)

Bağlantısız ve hızlı ama güvencesiz: handshake yoktur, her paket (datagram) bağımsız gönderilir; sıra ve teslim garanti edilmez. Java'da DatagramSocket ve DatagramPacket kullanılır.

DatagramSocket soket = new DatagramSocket();
soket.send(new DatagramPacket(veri, veri.length, adres, port));
soket.receive(paket);

Örnek 3 (./Ornek3.java) loopback üzerinde bir UDP gönder/al döngüsü gösterir. UDP; canlı video/ses, çevrim içi oyunlar ve DNS gibi hızın az kayıptan önemli olduğu yerlerde kullanılır.

TCPUDP
BağlantıVar (handshake)Yok
GüvenilirlikYüksek (sıralı, kayıpsız)Düşük (kayıp olabilir)
HızGörece yavaşHızlı
KullanımWeb, dosya, DBVideo/ses, oyun, DNS

Bloklama (blocking) ve thread'ler

Klasik soket API'si bloklayıcıdır: accept() bağlantı gelene, read() veri gelene kadar bekler. Bu yüzden gerçek sunucular her istemciyi ayrı bir thread'de (veya bir thread havuzunda) karşılar — böylece bir istemci diğerlerini bekletmez. Bunu bir sonraki konuda (Socket Programlama) çok istemcili bir sunucuyla göreceğiz. (Çok sayıda eşzamanlı bağlantı için Java 21'in sanal thread'leri burada büyük avantaj sağlar.)

Özet

Ağ programlamanın temel kavramlarını (IP, port, localhost/loopback, DNS, istemci/sunucu), adresleri tanımak için InetAddress'i ve iki taşıma protokolünü — güvenilir TCP ile hızlı UDP — kendi makinende çalışan örneklerle öğrendik. Sırada, TCP soketleriyle gerçek istemci- sunucu uygulamaları yazmayı derinleştiriyoruz: Socket Programlama.

Kod Örnekleri(3)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: InetAddress — makineleri ve IP adreslerini tanımak.
2// Ağ programlamanın ilk adımı: "kiminle konuşacağım?" — adres çözümleme.
3// Çalıştırma: java Ornek1.java
4import java.net.InetAddress;
5
6public class Ornek1 {
7
8    public static void main(String[] args) {
9        // Loopback (127.0.0.1 / ::1): her zaman "bu makinenin kendisi". İnternet gerektirmez.
10        InetAddress loopback = InetAddress.getLoopbackAddress();
11        System.out.println("Loopback adresi   : " + loopback.getHostAddress());
12
13        try {
14            // localhost adını çöz (loopback'e karşılık gelir).
15            InetAddress localhost = InetAddress.getByName("localhost");
16            System.out.println("localhost -> IP   : " + localhost.getHostAddress());
17
18            // Bu makinenin ağ adı ve IP'si.
19            InetAddress benim = InetAddress.getLocalHost();
20            System.out.println("Bu makine (ad)    : " + benim.getHostName());
21            System.out.println("Bu makine (IP)    : " + benim.getHostAddress());
22
23            // isReachable: hedefe ulaşılabilir mi? (loopback her zaman ulaşılabilir.)
24            System.out.println("Loopback erişilebilir mi? " + loopback.isReachable(1000));
25
26            // IPv4/IPv6 ayrımı:
27            System.out.println("\nLoopback IPv4 mü? " + (loopback instanceof java.net.Inet4Address));
28        } catch (Exception e) {
29            System.out.println("Adres çözümleme uyarısı: " + e.getMessage());
30        }
31
32        System.out.println("""
33
34                --- InetAddress ne işe yarar? ---
35                Ağda her makine bir IP adresiyle (IPv4: 192.168.1.5, IPv6: 2001:db8::1) tanınır.
36                İnsanlar adları (örn. example.com) kullanır; DNS bunları IP'ye çevirir.
37                InetAddress: ad<->IP çözümleme, loopback/localhost, ulaşılabilirlik testi sağlar.
38                (Bu örnek internet GEREKTİRMEZ; loopback ve yerel makineyle çalışır.)""");
39    }
40}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: TCP — güvenilir, bağlantı tabanlı iletişim (tek JVM'de echo sunucu + istemci).
2// Çalıştırma: java Ornek2.java
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStreamReader;
6import java.io.PrintWriter;
7import java.net.ServerSocket;
8import java.net.Socket;
9
10public class Ornek2 {
11
12    public static void main(String[] args) throws Exception {
13        // ServerSocket'i 0 (ephemeral) port ile açarız: işletim sistemi boş bir port atar.
14        ServerSocket sunucu = new ServerSocket(0);
15        int port = sunucu.getLocalPort();
16        System.out.println("TCP echo sunucusu başladı, port: " + port);
17
18        // Sunucu ayrı bir thread'de tek bir istemciyi karşılar (gelen satırı geri yansıtır).
19        Thread sunucuThread = new Thread(() -> {
20            try (Socket istemci = sunucu.accept(); // bağlantı bekle (bloklar)
21                 BufferedReader in = new BufferedReader(new InputStreamReader(istemci.getInputStream()));
22                 PrintWriter out = new PrintWriter(istemci.getOutputStream(), true)) {
23                String satir;
24                while ((satir = in.readLine()) != null) {
25                    System.out.println("  [sunucu] alındı: " + satir);
26                    out.println("ECHO: " + satir); // geri gönder
27                    if (satir.equals("bitir")) break;
28                }
29            } catch (IOException e) {
30                System.out.println("sunucu hatası: " + e.getMessage());
31            }
32        });
33        sunucuThread.start();
34
35        // İstemci: localhost:port'a bağlanır, mesaj gönderir, cevabı okur.
36        try (Socket soket = new Socket("localhost", port);
37             PrintWriter out = new PrintWriter(soket.getOutputStream(), true);
38             BufferedReader in = new BufferedReader(new InputStreamReader(soket.getInputStream()))) {
39            for (String mesaj : new String[]{"merhaba", "nasılsın", "bitir"}) {
40                out.println(mesaj);
41                System.out.println("[istemci] gönderdi: " + mesaj + " | cevap: " + in.readLine());
42            }
43        }
44
45        sunucuThread.join();
46        sunucu.close();
47        System.out.println("""
48
49                --- TCP (Transmission Control Protocol) ---
50                Bağlantı tabanlı, GÜVENİLİR: veri sırayla, kayıpsız ve doğrulanarak ulaşır.
51                Akış: ServerSocket.accept() bağlantı bekler; istemci Socket ile bağlanır.
52                Her iki taraf giriş/çıkış akışlarıyla (stream) konuşur — tıpkı dosya gibi.
53                HTTP, FTP, veritabanı bağlantıları... hepsi TCP üzerinde çalışır.""");
54    }
55}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek3

çalıştırılabilir
Ornek3.java
1// Ornek3: UDP — hızlı, bağlantısız iletişim (tek JVM'de datagram gönder/al).
2// Çalıştırma: java Ornek3.java
3import java.net.DatagramPacket;
4import java.net.DatagramSocket;
5import java.net.InetAddress;
6
7public class Ornek3 {
8
9    public static void main(String[] args) throws Exception {
10        InetAddress loopback = InetAddress.getLoopbackAddress();
11
12        // Sunucu tarafı: bir UDP soketi aç, bir paket bekle, cevap gönder.
13        DatagramSocket sunucu = new DatagramSocket(0); // ephemeral port
14        int port = sunucu.getLocalPort();
15        System.out.println("UDP sunucusu, port: " + port);
16
17        Thread sunucuThread = new Thread(() -> {
18            try {
19                byte[] tampon = new byte[1024];
20                DatagramPacket gelen = new DatagramPacket(tampon, tampon.length);
21                sunucu.receive(gelen); // paket bekle (bloklar)
22                String mesaj = new String(gelen.getData(), 0, gelen.getLength());
23                System.out.println("  [sunucu] alındı: " + mesaj);
24
25                // Cevabı, paketin geldiği adrese/porta geri gönder.
26                byte[] cevap = ("ECHO: " + mesaj).getBytes();
27                sunucu.send(new DatagramPacket(cevap, cevap.length, gelen.getAddress(), gelen.getPort()));
28            } catch (Exception e) {
29                System.out.println("sunucu hatası: " + e.getMessage());
30            }
31        });
32        sunucuThread.start();
33
34        // İstemci tarafı: bir paket gönder, cevabı al.
35        try (DatagramSocket istemci = new DatagramSocket()) {
36            byte[] veri = "merhaba UDP".getBytes();
37            istemci.send(new DatagramPacket(veri, veri.length, loopback, port));
38
39            byte[] tampon = new byte[1024];
40            DatagramPacket cevap = new DatagramPacket(tampon, tampon.length);
41            istemci.receive(cevap);
42            System.out.println("[istemci] cevap: " + new String(cevap.getData(), 0, cevap.getLength()));
43        }
44
45        sunucuThread.join();
46        sunucu.close();
47        System.out.println("""
48
49                --- UDP (User Datagram Protocol) ---
50                Bağlantısız, HIZLI ama GÜVENCESİZ: paket sırası/teslimi garanti edilmez.
51                Bağlantı kurma (handshake) yok; her paket (datagram) bağımsız gönderilir.
52                Kullanım: canlı video/ses, oyunlar, DNS — hızın, az kaybın önemli olmadığı yerler.
53                TCP vs UDP: TCP güvenilir+sıralı (web/dosya); UDP hızlı+kayıplı (gerçek zamanlı).""");
54    }
55}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.