JavaRush /Java blogi /Random-UZ /Socket va ServerSocket sinflari yoki “Salom, server? Sen ...
Sergey Simonov
Daraja
Санкт-Петербург

Socket va ServerSocket sinflari yoki “Salom, server? Sen meni eshitayapsanmi?"

Guruhda nashr etilgan
Kirish: “Stol ustida kompyuter bor edi, uning orqasida kodlovchi bor edi...” Socket va ServerSocket sinflari yoki “Salom, server?  Sen meni eshitayapsanmi?"  - 1 Bir paytlar sinfdoshlarimdan biri Java tilini o‘rganishning navbatdagi natijasini yangi dasturning skrinshoti ko‘rinishida e’lon qilgan edi. Ushbu dastur ko'p foydalanuvchili chat edi. O'sha paytda men ushbu tilda dasturlashni o'zlashtirish bo'yicha o'z sayohatimni endigina boshlagan edim, lekin men o'zimga "Men buni xohlayman!" Vaqt o'tdi va dasturlash bo'yicha bilimimni chuqurlashtirish doirasida keyingi loyiha ustida ishlashni tugatib, o'sha voqeani esladim va vaqt keldi deb qaror qildim. Qanday bo'lmasin, men bu mavzuni faqat qiziquvchanlik uchun qazishni boshladim, lekin mening asosiy Java darsligimda (bu Shildtning to'liq qo'llanmasi edi) java.net paketi uchun atigi 20 sahifa berilgan. Bu tushunarli - kitob allaqachon juda katta. Asosiy sinflarning usullari va konstruktorlari jadvallari mavjud edi, ammo bu hammasi. Keyingi qadam, albatta, qudratli Google: bir xil narsa taqdim etilgan ko'plab turli xil maqolalar - rozetkalar haqida ikki yoki uch so'z va tayyor misol. Klassik yondashuv (hech bo'lmaganda mening o'qish uslubim bo'yicha) birinchi navbatda ish uchun qanday vositalar kerakligini, ular nima ekanligini, nima uchun kerakligini tushunish va shundan keyingina, agar muammoning echimi aniq bo'lmasa, tayyor bo'lgan narsalar bilan shug'ullanishdir. - ro'yxatlar tuzdi, yong'oq va murvatlarni burang. Lekin men nima ekanligini tushundim va oxir-oqibat ko'p foydalanuvchi suhbatini yozdim. Tashqi ko'rinishiga ko'ra, shunday bo'lib chiqdi: Socket va ServerSocket sinflari yoki “Salom, server?  Sen meni eshitayapsanmi?"  - 2Bu erda men sizga chat dizayni misolida Java soketlariga asoslangan mijoz-server ilovalari asoslari haqida tushuncha berishga harakat qilaman. Javarash kursida siz suhbat qurasiz. Bu butunlay boshqacha darajada, chiroyli, katta, ko'p funktsiyali bo'ladi. Lekin birinchi navbatda, siz doimo poydevor qo'yishingiz kerak, shuning uchun bu erda biz bunday bo'limning asosini nima ekanligini aniqlashimiz kerak. (Agar siz biron bir kamchilik yoki xato topsangiz, PM yoki maqola ostidagi sharhda yozing). Keling, boshlaymiz. Birinchi bosh: "Uy ..." Server va bitta mijoz o'rtasida tarmoq ulanishi qanday sodir bo'lishini tushuntirish uchun, keling, ko'p qavatli uyning klassik misolini olaylik. Aytaylik, mijoz qandaydir tarzda ma'lum bir server bilan aloqa o'rnatishi kerak. Qidiruvchi qidiruv ob'ekti haqida nimani bilishi kerak? Ha, manzil. Server bulutdagi sehrli ob'ekt emas va shuning uchun u ma'lum bir mashinada joylashgan bo'lishi kerak. Ikki kelishilgan tomonning uchrashuvi bo'lishi kerak bo'lgan uyga o'xshab. Va ko'p qavatli uyda bir-birlarini topish uchun binoning bitta manzili etarli emas, siz uchrashuv bo'lib o'tadigan kvartiraning raqamini ko'rsatishingiz kerak. Xuddi shunday, bitta kompyuterda bir vaqtning o'zida bir nechta serverlar bo'lishi mumkin va mijoz ma'lum biriga murojaat qilishi uchun u ulanish amalga oshiriladigan port raqamini ham ko'rsatishi kerak. Shunday qilib, manzil va port raqami. Manzil Internet makonidagi mashina identifikatorini bildiradi. Bu domen nomi bo'lishi mumkin, masalan, "javarush.ru" , yoki oddiy IP. Port- ma'lum bir rozetka bilan bog'langan noyob raqam (bu atama keyinroq muhokama qilinadi), boshqacha qilib aytganda, u ma'lum bir xizmat tomonidan ishg'ol qilinadi, shunda u bilan bog'lanish uchun foydalanish mumkin. Shunday qilib, bitta (server) hududida kamida ikkita ob'ekt uchrashishi uchun hudud (server) egasi undagi (avtomobilda) ma'lum bir kvartirani (portni) egallashi kerak, ikkinchisi esa uchrashuv joyini bilishi kerak. uyning manzili (domen yoki ip ) va kvartira raqami (port). Ikkinchi bosh: Socket bilan tanishish Tarmoqda ishlash bilan bog'liq tushunchalar va atamalar orasida juda muhim biri bu Socket. U bog'lanish sodir bo'ladigan nuqtani bildiradi. Oddiy qilib aytganda, rozetka tarmoqdagi ikkita dasturni bog'laydi. Sinf Socketrozetka g'oyasini amalga oshiradi. Mijoz va server o'zining kirish/chiqish kanallari orqali muloqot qiladi: Socket va ServerSocket sinflari yoki “Salom, server?  Sen meni eshitayapsanmi?"  - 3 Bu sinf mijoz tomonida e'lon qilinadi va server ulanish signalini qabul qilib, uni qayta yaratadi. Onlayn muloqot shunday ishlaydi. Boshlash uchun, bu erda mumkin bo'lgan sinf konstruktorlari Socket:
Socket(String Name_хоста, int порт) throws UnknownHostException, IOException
Socket(InetAddress IP-address, int порт) throws UnknownHostException
"host_name" - ma'lum bir tarmoq tugunini, IP manzilini bildiradi. Agar rozetka klassi uni haqiqiy, mavjud manzilga aylantira olmasa, istisno qilinadi UnknownHostException. Port - bu port. Agar port raqami sifatida 0 ko'rsatilgan bo'lsa, tizimning o'zi bo'sh portni ajratadi. Aloqa yo'qolsa, istisno ham paydo bo'lishi mumkin IOException. Shuni ta'kidlash kerakki, ikkinchi konstruktorda manzil turi InetAddress. Bu, masalan, manzil sifatida domen nomini ko'rsatish kerak bo'lganda yordamga keladi. Bundan tashqari, agar domen bir nechta IP manzillarni bildirsa, InetAddresssiz ulardan bir qatorni olish uchun foydalanishingiz mumkin. Biroq, u IP bilan ham ishlaydi. Shuningdek, siz xost nomini, IP-manzilni tashkil etuvchi bayt massivini va hokazolarni olishingiz mumkin. Biz bu haqda biroz ko'proq gaplashamiz, ammo to'liq ma'lumot uchun rasmiy hujjatlarga o'tishingiz kerak bo'ladi. Turdagi ob'ekt ishga tushirilganda Socket, u tegishli bo'lgan mijoz tarmoqda ma'lum bir manzil va port raqami bo'yicha serverga ulanishni xohlayotganini e'lon qiladi. Quyida sinfning eng ko'p qo'llaniladigan usullari keltirilgan Socket: InetAddress getInetAddress()- rozetka haqidagi ma'lumotlarni o'z ichiga olgan ob'ektni qaytaradi. Agar rozetka ulanmagan bo'lsa - null int getPort()- serverga ulanish sodir bo'lgan portni qaytaradi int getLocalPort()- rozetka bog'langan portni qaytaradi. Gap shundaki, mijoz va server bitta portda "muloqot qilishlari" mumkin, ammo ular bog'langan portlar butunlay boshqacha bo'lishi mumkin boolean isConnected()- agar ulanish o'rnatilgan bo'lsa, haqiqatni qaytaradi void connect(SocketAddress address)- yangi ulanishni bildiradi boolean isClosed()- rozetka yopilgan bo'lsa, haqiqatni qaytaradi boolean isBound()- rostini qaytaradi, agar rozetka aslida manzilga bog'langan bo'lsa, sinf Socketinterfeysni amalga oshiradi AutoCloseable, shuning uchun uni try-with-resources. Shu bilan birga, siz klassik tarzda rozetkani close() yordamida yopishingiz mumkin. Uchinchi bosh: va bu ServerSocket Aytaylik, biz sinf ko'rinishida Socketmijoz tomonida ulanish so'rovini e'lon qildik. Server bizning xohishimizni qanday taxmin qiladi? Buning uchun serverda kabi sinf ServerSocketva unda accept() usuli mavjud. Uning konstruktorlari quyida keltirilgan:
ServerSocket() throws IOException
ServerSocket(int порт) throws IOException
ServerSocket(int порт, int максимум_подключений) throws IOException
ServerSocket(int порт, int максимум_подключений, InetAddress локальный_address) throws IOException
Deklaratsiya qilishda ServerSocket siz ulanish manzilini ko'rsatishingiz shart emas, chunki aloqa server mashinasida amalga oshiriladi. Faqat ko'p kanalli xost bilan server soketi qaysi IP ga bog'langanligini ko'rsatishingiz kerak. Uchinchi bosh: Yo'q deb aytadigan server Dasturni keraklidan ko'proq resurslar bilan ta'minlash qimmat va asossiz bo'lgani uchun konstruktorda ServerSocketsizdan ishlash vaqtida server tomonidan qabul qilingan maksimal ulanishlarni e'lon qilishingiz so'raladi. Agar u ko'rsatilmagan bo'lsa, u holda sukut bo'yicha bu raqam 50 ga teng deb hisoblanadi. Ha, nazariy jihatdan biz ServerSocketbu faqat server uchun bir xil rozetka deb taxmin qilishimiz mumkin. Lekin sinfdan ko'ra butunlay boshqacha rol o'ynaydi Socket. U faqat ulanishni yaratish bosqichida kerak bo'ladi. Turi ob'ektini yaratgandan so'ng, ServerSocketkimdir serverga ulanishni xohlayotganini aniqlashingiz kerak. Bu yerda accept() usuli ulangan. Maqsad kimdir unga ulanishni xohlamaguncha kutadi va bu sodir bo'lganda, u turdagi ob'ektni Socket, ya'ni qayta yaratilgan mijoz soketini qaytaradi. Va endi mijoz soketi server tomonida yaratilgan, ikki tomonlama aloqa boshlanishi mumkin. SocketMijoz tomonida turdagi ob'ektni yaratish va uni ServerSocketserver tomoni yordamida qayta yaratish ulanish uchun minimal talab qilinadi. To'rtinchi bosh: Santa Klausga maktub Вопрос: Mijoz va server aniq qanday aloqa qiladi? Ответ:I/U oqimlari orqali. Bizda allaqachon nima bor? Server manzili va mijozning port raqamiga ega rozetka va xuddi shu narsa server tomonidagi accept() tufayli. Shunday qilib, ular rozetka orqali muloqot qilishadi deb taxmin qilish oqilona. Buning uchun oqimlar InputStreamva OutputStreamturdagi ob'ektlarga kirish imkonini beruvchi ikkita usul mavjud Socket. Mana ular:
InputStream getInputStream()
OutputStream getOutputStream()
Yalang'och baytlarni o'qish va yozish unchalik samarali emasligi sababli, oqimlarni adapter sinflariga o'rash mumkin, buferlangan yoki yo'q. Masalan:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Aloqa ikki tomonlama bo'lishi uchun bunday operatsiyalar har ikki tomonda ham bajarilishi kerak. Endi siz in yordamida biror narsani yuborishingiz va out yordamida biror narsani qabul qilishingiz mumkin va aksincha. Aslida, bu sinfning amalda yagona funktsiyasi Socket. Ha, flush() usuli haqida unutmang BufferedWriter- bu bufer tarkibini tozalaydi. Agar bu bajarilmasa, ma'lumot uzatilmaydi va shuning uchun qabul qilinmaydi. Qabul qiluvchi ip ham qator oxiri indikatorini kutadi - “\n”, aks holda xabar qabul qilinmaydi, chunki aslida xabar tugallanmagan va to'liq emas. Agar bu sizga noqulay boʻlib tuyulsa, xavotir olmang, siz har doim oʻrashingiz, ikkinchi argument sifatida true ni belgilashingiz kerak boʻlgan class dan foydalanishingiz mumkin PrintWriter, soʻngra buferdan chiqish avtomatik ravishda sodir boʻladi:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
Bundan tashqari, chiziq oxirini ko'rsatishning hojati yo'q; bu sinf buni siz uchun qiladi. Lekin I/U qatori rozetka qila oladigan chegarami? Yo'q, ob'ektlarni rozetkalar orqali jo'natmoqchimisiz? Xudo uchun. Ularni ketma-ketlashtiring va ketishingiz mumkin:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Beshinchi bosh: Internet orqali haqiqiy aloqa Haqiqiy IP-manzilga ega haqiqiy tarmoq orqali ulanish uchun siz to'liq huquqli serverga ega bo'lishingiz kerak, chunki:
  1. Bizning kelajakdagi suhbatimiz, yordamchi dastur sifatida, bunday qobiliyatlarga ega emas. U faqat ulanish o'rnatishi va xabarni qabul qilishi/yuborishi mumkin. Ya'ni, u haqiqiy server imkoniyatlariga ega emas.
  2. Faqat rozetka ma'lumotlari va kiritish-chiqarish oqimlarini o'z ichiga olgan serverimiz haqiqiy WEB yoki FTP serveri sifatida ishlay olmaydi, faqat shu bilan biz Internet orqali ulana olmaymiz.
Bundan tashqari, biz dasturni endigina ishlab chiqayapmiz, ya'ni u darhol haqiqiy tarmoq bilan ishlash uchun etarlicha barqaror emas, shuning uchun biz ulanish manzili sifatida mahalliy xostdan foydalanamiz. Ya'ni, nazariy jihatdan, mijoz va server hali ham rozetkadan tashqari hech qanday tarzda ulanmaydi, lekin dasturni tuzatish uchun ular tarmoq orqali haqiqiy aloqasiz bir xil mashinada bo'ladi. Konstruktorda Socketmanzil mahalliy ekanligini ko'rsatish uchun ikkita usul mavjud:
  1. Manzil argumenti sifatida “localhost” ni yozing, bu mahalliy stubni anglatadi. Buning uchun "127.0.0.1" ham mos keladi - bu shunchaki stubning raqamli shakli.
  2. InetAddressdan foydalanish:
    1. InetAddress.getByName(null)- null localhost-ga ishora qiladi
    2. InetAddress.getByName("localhost")
    3. InetAddress.getByName("127.0.0.1")
Oddiylik uchun biz String tipidagi "localhost" dan foydalanamiz. Ammo boshqa barcha variantlar ham ishlaydi. Oltinchi bosh: Suhbat vaqti keldi Shunday qilib, bizda server bilan suhbat sessiyasini amalga oshirish uchun kerak bo'lgan hamma narsa mavjud. Qolgan narsa uni bir joyga qo'yishdir: Quyidagi ro'yxat mijozning serverga qanday ulanishini ko'rsatadi, unga bitta xabar yuboradi va server, o'z navbatida, xabarni o'zining argumenti sifatida qabul qilganligini tasdiqlaydi: "Server. java"
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    private static Socket clientSocket; // socket for communication
    private static ServerSocket server; // server socket
    private static BufferedReader in; // socket read stream
    private static BufferedWriter out; // socket write stream

    public static void main(String[] args) {
        try {
            try  {
                server = new ServerSocket(4004); // server socket listening on port 4004
                System.out.println("Server is running!"); // server would be nice
                // announce your launch
                clientSocket = server.accept(); // accept() will wait until
                //someone won't want to connect
                try { // after establishing a connection and recreating the socket for communication with the client, you can go
                    // to create I/O streams.
                    // now we can receive messages
                    in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    // and send
                    out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

                    String word = in.readLine(); // wait for the client to write something to us
                    System.out.println(word);
                    // without hesitation responds to the client
                    out.write("Hi, this is the Server! I confirm you wrote: " + word + "\n");
                    out.flush(); // push everything out of the buffer

                } finally { // in any case, the socket will be closed
                    clientSocket.close();
                    // streams would also be nice to close
                    in.close();
                    out.close();
                }
            } finally {
                System.out.println("Server closed!");
                    server.close();
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }
"Client.java"
import java.io.*;
import java.net.Socket;

public class Client {

    private static Socket clientSocket; // socket for communication
    private static BufferedReader reader; // we need a reader that reads from the console, otherwise
    // do we know what the client wants to say?
    private static BufferedReader in; // socket read stream
    private static BufferedWriter out; // socket write stream

    public static void main(String[] args) {
        try {
            try {
                // address - local host, port - 4004, same as the server
                clientSocket = new Socket("localhost", 4004); // with this line we request
                // the server has access to the connection
                reader = new BufferedReader(new InputStreamReader(System.in));
                // read messages from the server
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                // write there
                out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

                System.out.println("Did you have something to say? Enter it here:");
                // if the connection happened and the threads were successfully created - we can
                // work further and offer the client something to enter
                // if not, an exception will be thrown
                String word = reader.readLine(); // wait for the client to do something
                // will not write to the console
                out.write(word + "\n"); // send a message to the server
                out.flush();
                String serverWord = in.readLine(); // wait for the server to say
                System.out.println(serverWord); // received - display
            } finally { // in any case, you need to close the socket and streams
                System.out.println("The client has been closed...");
                clientSocket.close();
                in.close();
                out.close();
            }
        } catch (IOException e) {
            System.err.println(e);
        }

    }
}
Albatta, siz avval serverni ishga tushirishingiz kerak, chunki mijoz ishga tushganda uni bog'laydigan biror narsa bo'lmasa nimaga ulanadi? :) Chiqish shunday bo'ladi: /* Nimadir demoqchimisiz? Bu yerga kiriting: Salom, server? Sen meni eshitayapsanmi? Salom, bu Server! Tasdiqlayman, siz yozdingiz: Salom, server? Sen meni eshitayapsanmi? Mijoz yopildi... */ Huray! Biz serverga mijoz bilan muloqot qilishni o'rgatganmiz! Aloqa ikki nusxada emas, balki xohlaganingizcha sodir bo'lishi uchun, shunchaki iplarni o'qish va yozishni vaqtinchalik (haqiqiy) tsiklga o'rang va chiqish uchun ma'lum bir xabarga ko'ra, masalan, "chiqish" ni ko'rsating. , tsikl to'xtatildi va dastur tugaydi. Yettinchi bosh: Ko‘p foydalanuvchili yaxshi.Server bizni eshita olishi yaxshi, lekin o‘zimizdan biri bilan muloqot qilsak yaxshi bo‘lardi. Maqolaning oxirida men barcha manbalarni qo'shaman, shuning uchun bu erda men har doim ham katta emas, lekin to'g'ri ishlatilsa, ko'p foydalanuvchili suhbatni yaratishga imkon beradigan muhim kod qismlarini ko'rsataman. Shunday qilib, biz server orqali boshqa mijoz bilan bog'lanishni xohlaymiz. Buni qanday qilish kerak? Shubhasiz, mijoz dasturining o'z usuli borligi sababli main, u serverdan alohida va boshqa mijozlar bilan parallel ravishda ishga tushirilishi mumkinligini anglatadi. Bu bizga nima beradi? Qanday bo'lmasin, har bir yangi ulanish bilan server darhol aloqaga o'tmasligi kerak, lekin bu ulanishni qandaydir ro'yxatga yozib qo'yadi va yangi ulanishni kutishni davom ettiradi va qandaydir yordamchi xizmat ma'lum bir aloqa bilan shug'ullanadi. mijoz. Va mijozlar serverga yozishlari va bir-biridan mustaqil ravishda javob kutishlari kerak. Iplar yordamga keladi. Aytaylik, bizda yangi ulanishlarni eslab qolish uchun mas'ul sinf bor: Unda quyidagilar ko'rsatilgan bo'lishi kerak:
  1. Port raqami.
  2. Yangi ulanishni yozadigan ro'yxat.
  3. Va ServerSocket, bitta (!) nusxada.
public class Server {

    public static final int PORT = 8080;
    public static LinkedList<ServerSomthing> serverList = new LinkedList<>(); // list of all threads

    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(PORT);
            try {
            while (true) {
                // Blocks until a new connection is made:
                Socket socket = server.accept();
                try {
                    serverList.add(new ServerSomthing(socket)); // add a new connection to the list
                } catch (IOException e) {
                    // If it fails, the socket is closed,
                    // otherwise, the thread will close it when it exits:
                    socket.close();
                }
            }
        } finally {
            server.close();
        }
    }
}
OK, endi har bir qayta yaratilgan rozetka yo'qolmaydi, lekin serverda saqlanadi. Keyinchalik. Har bir mijoz tinglash uchun kimdir kerak. Oxirgi bobdan server funksiyalari bilan ip yaratamiz.
class ServerSomthing extends Thread {

    private Socket socket; // socket through which the server communicates with the client,
    // except for it - the client and server are not connected in any way
    private BufferedReader in; // socket read stream
    private BufferedWriter out; // socket write stream

    public ServerSomthing(Socket socket) throws IOException {
        this.socket = socket;
        // если потоку ввода/вывода приведут к генерированию исключения, оно пробросится дальше
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        start(); // call run()
    }
    @Override
    public void run() {
        String word;
        try {

            while (true) {
                word = in.readLine();
                if(word.equals("stop")) {
                    break;                }
                for (ServerSomthing vr : Server.serverList) {
                    vr.send(word); // send the received message with
                   // bound client to everyone else including him
                }
            }

        } catch (IOException e) {
        }
    }

    private void send(String msg) {
        try {
            out.write(msg + "\n");
            out.flush();
        } catch (IOException ignored) {}
    }
}
Shunday qilib, server ipining konstruktorida rozetka ishga tushirilishi kerak, u orqali ip ma'lum bir mijoz bilan bog'lanadi. Bundan tashqari, kiritish/chiqarish iplari va to'g'ridan-to'g'ri konstruktordan ipni boshlashingiz kerak bo'lgan boshqa narsalar. Yaxshi, lekin server tarmog'i mijozdan kelgan xabarni o'qisa nima bo'ladi? Faqat mijozingizga qaytarib yuborilsinmi? Juda samarali emas. Biz ko'p foydalanuvchili chat qurmoqdamiz, shuning uchun bizga har bir ulangan mijoz bir kishi yozgan narsani olishi kerak. Siz o'z mijozlari bilan bog'langan barcha server oqimlari ro'yxatidan foydalanishingiz va har bir xabarni o'z mijoziga yuborishi uchun ma'lum bir mavzuga yuborishingiz kerak:
for (ServerSomthing vr : Server.serverList) {
    vr.send(word); // send the received message
    // from the linked client to everyone else, including him
}
private void send(String msg) {
    try {
        out.write(msg + "\n");
        out.flush();
    } catch (IOException ignored) {}
}
Endi barcha mijozlar ulardan biri nima deganini bilib oladi! Agar siz xabarni yuborgan shaxsga yuborilishini istamasangiz (u nima yozganini allaqachon biladi!), shunchaki iplar bo'ylab takrorlashda, ob'ektni qayta ishlashda sikl thiskeyingi elementga o'tishini belgilang. unga nisbatan har qanday harakatlar. Yoki, agar xohlasangiz, mijozga xabar muvaffaqiyatli qabul qilingani va yuborilganligi haqida xabar yuboring. Serverda hamma narsa aniq. Keling, mijozga, to'g'rirog'i, mijozlarga o'tamiz! U erda hamma narsa bir xil, oxirgi bobdagi mijozga o'xshab, faqat misol yaratishda, bu bobda server bilan ko'rsatilganidek, konstruktorda kerak bo'lgan hamma narsani yaratish kerak. Agar mijozni yaratishda u hali biror narsa kiritishga ulgurmagan bo'lsa-chi, lekin unga biror narsa yuborilgan bo'lsa-chi? (Masalan, undan oldin chatga ulanganlarning yozishmalari tarixi). Shunday qilib, yuborilgan xabarlar qayta ishlanadigan tsikllar konsoldan xabarlar o'qiladigan va boshqalarga yo'naltirish uchun serverga yuboriladigan davrlardan ajratilishi kerak. Iplar yana yordamga keladi. Mijozni ip sifatida yaratishning ma'nosi yo'q. Run usulida xabarlarni o'qiydigan, shuningdek, analogiya bo'yicha yozadigan halqali ipni yaratish qulayroqdir:
// thread reading messages from the server
private class ReadMsg extends Thread {
    @Override
    public void run() {

        String str;
        try {
            while (true) {
                str = in.readLine(); // waiting for a message from the server
                if (str.equals("stop")) {

                    break; // exit the loop if it's "stop"
                }
                            }
        } catch (IOException e) {

        }
    }
}
// thread sending messages coming from the console to the server
public class WriteMsg extends Thread {

    @Override
    public void run() {
        while (true) {
            String userWord;
            try {
               userWord = inputUser.readLine(); // messages from the console
                if (userWord.equals("stop")) {
                    out.write("stop" + "\n");
                    break; // exit the loop if it's "stop"
                } else {
                    out.write(userWord + "\n"); // send to the server
                }
                out.flush(); // clean up
            } catch (IOException e) {

            }

        }
    }
}
Mijoz konstruktorida siz shunchaki ushbu mavzularni boshlashingiz kerak. Agar mijoz ketmoqchi bo'lsa, uning resurslarini qanday qilib to'g'ri yopish kerak? Men server ip resurslarini yopishim kerakmi? Buni amalga oshirish uchun siz xabarlar siklidan chiqishda chaqiriladigan alohida usulni yaratishingiz kerak bo'ladi. U erda siz rozetkani va I/U oqimlarini yopishingiz kerak bo'ladi. Muayyan mijoz uchun xuddi shu seansni tugatish signali uning server tarmog'iga yuborilishi kerak, u o'z rozetkasi bilan xuddi shunday qilishi va o'zini asosiy server sinfidagi iplar ro'yxatidan olib tashlashi kerak. Sakkizinchi bosh: mukammallikka cheklov yo'q. Loyihangizni yaxshilash uchun cheksiz yangi xususiyatlarni ixtiro qilishingiz mumkin. Lekin yangi ulangan mijozga aynan nimani o'tkazish kerak? O'ylaymanki, oxirgi o'nta voqea uning kelishidan oldin sodir bo'lgan. Buni amalga oshirish uchun siz e'lon qilingan ro'yxatga istalgan server oqimi bilan oxirgi amal kiritiladigan sinf yaratishingiz kerak va agar ro'yxat allaqachon to'lgan bo'lsa (ya'ni 10 tasi bor), birinchisini o'chiring va qo'shing. oxirgi kelgan. Ushbu ro'yxatning mazmuni yangi ulanish orqali qabul qilinishi uchun, server oqimini yaratishda, chiqish oqimida siz ularni mijozga yuborishingiz kerak. Buni qanday qilish kerak? Masalan, bu kabi:
public void printStory(BufferedWriter writer) {
// ...
}
Server oqimi allaqachon oqimlarni yaratgan va chiqish oqimini argument sifatida uzatishi mumkin. Keyinchalik, qidiruv siklida yangi mijozga o'tkazilishi kerak bo'lgan hamma narsani o'tkazishingiz kerak. Xulosa: Bu shunchaki asoslar va bu chat arxitekturasi haqiqiy dastur yaratishda ishlamasligi mumkin. Ushbu dastur ta'lim maqsadlari uchun yaratilgan va uning asosida men mijozni server bilan qanday bog'lashingiz mumkinligini (va aksincha), buni bir nechta ulanishlar uchun qanday qilish kerakligini va, albatta, rozetkalarda qanday tashkil etilishini ko'rsatdim. Quyida manbalar qayta tartiblangan va tahlil qilinayotgan dasturning manba kodi ham ilova qilingan. Bu mening maqola yozishdagi birinchi tajribam) E'tiboringiz uchun rahmat :)
  1. Java Enterprise-da fikrlash, Bryus Ekkel va boshqalar. Al. 2003 yil
  2. Java 8, To'liq qo'llanma, Gerbert Shildt, 9-nashr, 2017 (22-bob)
  3. Java-da rozetkalarni dasturlash rozetkalar haqidagi maqola
  4. Rasmiy hujjatlardagi rozetka
  5. Rasmiy hujjatlarda ServerSocket
  6. GitHub-dagi manbalar
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION