JavaRush /Java Blog /Random-TL /Ang mga klase ng Socket at ServerSocket, o “Hello, server...
Sergey Simonov
Antas
Санкт-Петербург

Ang mga klase ng Socket at ServerSocket, o “Hello, server? Naririnig mo ba ako?"

Nai-publish sa grupo
Panimula: “May computer sa mesa, sa likod nito ay may encoder...” Ang mga klase ng Socket at ServerSocket, o “Hello, server?  Naririnig mo ba ako?"  - 1 Noong unang panahon, ang isa sa aking mga kaklase ay nag-post ng isa pang resulta ng kanyang pag-aaral ng Java, sa anyo ng isang screenshot ng isang bagong programa. Ang program na ito ay isang multi-user na chat. Sa oras na iyon ay nagsisimula pa lang ako sa sarili kong paglalakbay sa pag-master ng programming sa wikang ito, ngunit tiyak na nabanggit ko sa aking sarili na "Gusto ko ito!" Lumipas ang oras at, nang matapos akong magtrabaho sa susunod na proyekto bilang bahagi ng pagpapalalim ng aking kaalaman sa programming, naalala ko ang pangyayaring iyon at nagpasya na oras na. Kahit papaano ay nagsimula na akong maghukay sa paksang ito dahil lamang sa kuryusidad, ngunit sa aking pangunahing aklat-aralin sa Java (ito ay kumpletong manwal ng Schildt) 20 na pahina lamang ang ibinigay para sa java.net package. Ito ay maliwanag - ang aklat ay napakalaki na. Mayroong mga talahanayan ng mga pamamaraan at tagabuo ng mga pangunahing klase, ngunit iyon lang. Ang susunod na hakbang ay, siyempre, ang makapangyarihang Google: napakaraming iba't ibang mga artikulo kung saan ang parehong bagay ay ipinakita - dalawa o tatlong salita tungkol sa mga socket, at isang handa na halimbawa. Ang klasikong diskarte (kahit sa aking istilo ng pag-aaral) ay unang maunawaan kung ano ang kailangan ko mula sa mga tool para sa trabaho, kung ano ang mga ito, kung bakit kailangan ang mga ito, at pagkatapos lamang, kung ang solusyon sa problema ay hindi halata, pumili sa ang mga nakahanda nang listahan, inaalis ang takip ng mga mani at bolts. Ngunit nalaman ko kung ano ang at sa huli ay nagsulat ng isang multi-user na chat. Sa panlabas, naging ganito: Ang mga klase ng Socket at ServerSocket, o “Hello, server?  Naririnig mo ba ako?"  - 2Dito susubukan kong bigyan ka ng pag-unawa sa mga pangunahing kaalaman ng mga application ng client-server batay sa mga Java socket gamit ang halimbawa ng disenyo ng chat. Sa kursong Javarash gagawa ka ng chat. Ito ay magiging sa isang ganap na naiibang antas, maganda, malaki, multifunctional. Ngunit una sa lahat, kailangan mong palaging ilagay ang pundasyon, kaya narito kailangan nating malaman kung ano ang pinagbabatayan ng naturang seksyon. (Kung makakita ka ng anumang mga pagkukulang o pagkakamali, sumulat sa isang PM o sa isang komento sa ilalim ng artikulo). Magsimula tayo. Head One: "Ang bahay na..." Upang ipaliwanag kung paano nangyayari ang isang koneksyon sa network sa pagitan ng isang server at isang kliyente, kunin natin ang klasikong halimbawa na ngayon ng isang gusali ng apartment. Sabihin nating kailangan ng isang kliyente na kahit papaano ay magtatag ng koneksyon sa isang partikular na server. Ano ang kailangang malaman ng naghahanap tungkol sa bagay sa paghahanap? Oo, ang address. Ang server ay hindi isang mahiwagang entity sa cloud, at samakatuwid dapat itong matatagpuan sa isang partikular na makina. Sa pamamagitan ng pagkakatulad sa isang bahay, kung saan ang isang pulong ng dalawang napagkasunduan sa mga partido ay dapat maganap. At upang mahanap ang isa't isa sa isang gusali ng apartment, hindi sapat ang isang address ng gusali; dapat mong ipahiwatig ang bilang ng apartment kung saan magaganap ang pulong. Gayundin, sa isang computer ay maaaring magkaroon ng ilang mga server nang sabay-sabay, at upang ang kliyente ay makipag-ugnay sa isang tiyak, kailangan din niyang tukuyin ang numero ng port kung saan magaganap ang koneksyon. Kaya, ang address at numero ng port. Ang isang address ay nangangahulugang isang identifier ng isang makina sa espasyo ng Internet. Maaari itong maging isang domain name, halimbawa, "javarush.ru" , o isang regular na IP. Port- isang natatanging numero kung saan nauugnay ang isang partikular na socket (tatalakayin ang terminong ito sa ibang pagkakataon), sa madaling salita, ito ay inookupahan ng isang tiyak na serbisyo upang magamit ito upang makipag-ugnay dito. Kaya't upang magtagpo ang hindi bababa sa dalawang bagay sa teritoryo ng isa (server), ang may-ari ng lugar (server) ay dapat maghawak ng isang partikular na apartment (port) dito (kotse), at ang pangalawa ay dapat mahanap ang lugar ng pagpupulong na alam ang address ng bahay (domain o ip ), at numero ng apartment (port). Head Two: Meet Socket Kabilang sa mga konsepto at terminong nauugnay sa pagtatrabaho sa network, ang isang napakahalaga ay ang Socket. Tinutukoy nito ang punto kung saan nangyayari ang koneksyon. Sa madaling salita, ang isang socket ay nagkokonekta sa dalawang programa sa isang network. Ipinapatupad ng klase Socketang ideya ng isang socket. Ang kliyente at ang server ay makikipag-usap sa pamamagitan ng mga channel ng input/output nito: Ang mga klase ng Socket at ServerSocket, o “Hello, server?  Naririnig mo ba ako?"  - 3 Ang klase na ito ay idineklara sa panig ng kliyente, at muling nililikha ito ng server, na tumatanggap ng signal ng koneksyon. Ito ay kung paano gumagana ang online na komunikasyon. Upang magsimula, narito ang mga posibleng tagabuo ng klase Socket:
Socket(String Name_хоста, int порт) throws UnknownHostException, IOException
Socket(InetAddress IP-address, int порт) throws UnknownHostException
"host_name" - nagpapahiwatig ng isang partikular na network node, IP address. Kung hindi ito ma-convert ng socket class sa isang tunay, umiiral na address, kung gayon ang isang pagbubukod ay itatapon UnknownHostException. Ang daungan ay isang daungan. Kung ang 0 ay tinukoy bilang numero ng port, ang system mismo ay maglalaan ng isang libreng port. Ang isang pagbubukod ay maaari ding mangyari kung ang koneksyon ay nawala IOException. Dapat tandaan na ang uri ng address sa pangalawang tagabuo ay InetAddress. Ito ay dumating sa pagsagip, halimbawa, kapag kailangan mong tukuyin ang isang domain name bilang isang address. Gayundin, kapag ang isang domain ay nangangahulugan ng ilang mga IP address, InetAddressmaaari mong gamitin ang mga ito upang makakuha ng isang hanay ng mga ito. Gayunpaman, gumagana din ito sa IP. Maaari mo ring makuha ang pangalan ng host, ang byte array na bumubuo sa IP address, atbp. Susubukan naming hawakan ito nang kaunti pa, ngunit kailangan mong pumunta sa opisyal na dokumentasyon para sa buong detalye. Kapag nasimulan ang isang bagay na may uri Socket, ang kliyenteng kinabibilangan nito ay mag-aanunsyo sa network na gusto nitong kumonekta sa server sa isang partikular na address at numero ng port. Nasa ibaba ang pinakamadalas na ginagamit na pamamaraan ng klase Socket: InetAddress getInetAddress()– nagbabalik ng isang bagay na naglalaman ng data tungkol sa socket. Kung ang socket ay hindi konektado - null int getPort()- ibinabalik ang port kung saan ang koneksyon sa server ay nangyayari int getLocalPort()- ibabalik ang port kung saan ang socket ay nakatali. Ang katotohanan ay ang kliyente at server ay maaaring "makipag-usap" sa isang port, ngunit ang mga port kung saan sila nakatali ay maaaring maging ganap na naiiba boolean isConnected()- babalik ng totoo kung ang koneksyon ay naitatag void connect(SocketAddress address)- nagpapahiwatig ng isang bagong koneksyon boolean isClosed()- nagbabalik ng totoo, kung ang socket ay sarado boolean isBound()- nagbabalik ng totoo, kung ang socket ay aktwal na nakatali sa isang address, Socketipinapatupad ng klase ang interface AutoCloseable, upang magamit ito sa try-with-resources. Gayunpaman, maaari mo ring isara ang isang socket sa klasikong paraan, gamit ang close(). Ikatlong Ulo: at ito ay isang ServerSocket Sabihin nating ipinahayag namin, sa anyo ng isang klase Socket, isang kahilingan sa koneksyon sa panig ng kliyente. Paano mahulaan ng server ang aming nais? Para dito, ang server ay may klase tulad ng ServerSocket, at ang accept() na paraan dito. Ang mga konstruktor nito ay ipinakita sa ibaba:
ServerSocket() throws IOException
ServerSocket(int порт) throws IOException
ServerSocket(int порт, int максимум_подключений) throws IOException
ServerSocket(int порт, int максимум_подключений, InetAddress локальный_address) throws IOException
Kapag nagdedeklara, ServerSocket hindi mo kailangang tukuyin ang address ng koneksyon, dahil ang komunikasyon ay nagaganap sa server machine. Sa isang multi-channel host lang kailangan mong tukuyin kung aling IP ang server socket ay nakasalalay. Head Three.One: The Server That Says No Dahil ang pagbibigay ng program na may mas maraming mapagkukunan kaysa sa kailangan nito ay parehong magastos at hindi makatwiran, samakatuwid sa constructor ServerSockethihilingin sa iyo na ideklara ang pinakamataas na koneksyon na tinatanggap ng server sa panahon ng operasyon. Kung hindi ito tinukoy, kung gayon bilang default ang numerong ito ay ituturing na katumbas ng 50. Oo, sa teorya maaari nating ipagpalagay na ServerSocketito ay ang parehong socket, para lamang sa server. Ngunit ito ay gumaganap ng isang ganap na naiibang papel kaysa sa klase Socket. Ito ay kinakailangan lamang sa yugto ng paglikha ng koneksyon. Ang pagkakaroon ng paglikha ng isang uri ng bagay, ServerSocketkailangan mong malaman na may gustong kumonekta sa server. Ang accept() method ay konektado dito. Naghihintay ang target hanggang sa may gustong kumonekta dito, at kapag nangyari ito, ibabalik nito ang isang object ng uri Socket, iyon ay, isang muling nilikhang socket ng kliyente. At ngayon na ang client socket ay nagawa na sa gilid ng server, maaaring magsimula ang two-way na komunikasyon. Ang paglikha ng isang uri ng bagay Socketsa panig ng kliyente at muling paggawa nito gamit ServerSocketang panig ng server ay ang minimum na kinakailangan para sa koneksyon. Apat na Ulo: Liham kay Santa Claus Вопрос: Paano eksaktong nakikipag-usap ang kliyente at server? Ответ:Sa pamamagitan ng I/O stream. Ano na meron tayo? Isang socket na may address ng server at numero ng port ng kliyente, at ang parehong bagay, salamat sa pagtanggap(), sa gilid ng server. Kaya't makatwirang ipagpalagay na makikipag-usap sila sa pamamagitan ng isang socket. Upang gawin ito, mayroong dalawang paraan na nagbibigay ng access sa mga stream InputStreamat OutputStreamobject ng uri Socket. Nandito na sila:
InputStream getInputStream()
OutputStream getOutputStream()
Dahil ang pagbabasa at pagsusulat ng mga hubad na byte ay hindi kasing episyente, ang mga stream ay maaaring ibalot sa mga klase ng adaptor, buffer o hindi. Halimbawa:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Para maging bidirectional ang komunikasyon, ang mga naturang operasyon ay dapat gawin sa magkabilang panig. Ngayon ay maaari kang magpadala ng isang bagay gamit ang in, at makatanggap ng isang bagay gamit out, at vice versa. Sa totoo lang, halos ito lang ang function ng klase Socket. At oo, huwag kalimutan ang tungkol sa flush() na paraan BufferedWriter- pinapa-flush nito ang mga nilalaman ng buffer. Kung hindi ito gagawin, ang impormasyon ay hindi ipapadala at, samakatuwid, ay hindi matatanggap. Ang receiving thread ay naghihintay din para sa end-of-line indicator – “\n”, kung hindi, ang mensahe ay hindi tatanggapin, dahil sa katunayan ang mensahe ay hindi nakumpleto at hindi kumpleto. Kung ito ay tila hindi maginhawa sa iyo, huwag mag-alala, maaari mong palaging gamitin ang class PrintWriter, na kailangang i-wrap out, tukuyin ang true bilang pangalawang argumento, at pagkatapos ay awtomatikong magaganap ang pag-pop mula sa buffer:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
Gayundin, hindi na kailangang ipahiwatig ang dulo ng linya; ginagawa ito ng klase para sa iyo. Ngunit ang string I/O ba ang limitasyon ng magagawa ng socket? Hindi, gusto mo bang magpadala ng mga bagay sa pamamagitan ng mga socket stream? Para sa kapakanan ng Diyos. I-serialize ang mga ito at handa ka nang umalis:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Head Five: Tunay na komunikasyon sa pamamagitan ng Internet Dahil upang kumonekta sa pamamagitan ng isang tunay na network na may isang tunay na IP address kailangan mong magkaroon ng isang ganap na server, at dahil:
  1. Ang aming hinaharap na chat, bilang isang utility, ay walang ganoong kakayahan. Maaari lamang itong magtatag ng koneksyon at tumanggap/magpadala ng mensahe. Ibig sabihin, wala itong tunay na kakayahan ng server.
  2. Ang aming server, na naglalaman lamang ng socket data at I/O stream, ay hindi maaaring gumana bilang isang tunay na WEB o FTP server, at sa pamamagitan lamang nito ay hindi na kami makakakonekta sa Internet.
At bukod pa, nagsisimula pa lang kaming bumuo ng programa, na nangangahulugan na hindi ito sapat na matatag upang agad na magtrabaho sa isang tunay na network, kaya gagamitin namin ang lokal na host bilang address ng koneksyon. Iyon ay, sa teorya, ang kliyente at server ay hindi pa rin makakonekta sa anumang paraan maliban sa pamamagitan ng isang socket, ngunit para sa pag-debug ng programa sila ay nasa parehong makina, nang walang tunay na pakikipag-ugnayan sa network. Upang ipahiwatig sa constructor Socketna ang address ay lokal, mayroong 2 paraan:
  1. Isulat ang "localhost" bilang argumento ng address, ibig sabihin ay isang lokal na stub. Angkop din ang "127.0.0.1" para dito - isa lang itong digital form ng stub.
  2. Gamit ang InetAddress:
    1. InetAddress.getByName(null)- null point sa localhost
    2. InetAddress.getByName("localhost")
    3. InetAddress.getByName("127.0.0.1")
Para sa pagiging simple, gagamitin namin ang "localhost" ng uri ng String. Ngunit lahat ng iba pang mga pagpipilian ay magagawa rin. Head Six: Oras na para sa isang pag-uusap Kaya, mayroon na kami ng lahat ng kailangan namin upang ipatupad ang isang session ng pag-uusap sa server. Ang natitira na lang ay pagsasama-samahin ito: Ang sumusunod na listahan ay nagpapakita kung paano kumokonekta ang kliyente sa server, ipinapadala ito ng isang mensahe, at ang server naman, ay nagpapatunay na natanggap nito ang mensahe gamit ito bilang argumento sa: "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);
        }

    }
}
Siyempre, dapat mong simulan muna ang server, dahil ano ang ikokonekta ng kliyente sa pagsisimula kung walang isang bagay na magkokonekta dito? :) Magiging ganito ang output: /* May gusto ka bang sabihin? Ilagay ito dito: Hello, server? Naririnig mo ba ako? Hello, ito ang Server! Kinukumpirma ko, isinulat mo: Hello, server? Naririnig mo ba ako? Sarado ang kliyente... */ Hurray! Tinuruan namin ang server na makipag-usap sa kliyente! Upang ang komunikasyon ay hindi nangyayari sa dalawang replika, ngunit hangga't gusto mo, balutin lamang ang pagbabasa at pagsulat ng mga thread sa ilang sandali (totoo) na loop at ipahiwatig para sa exit na, ayon sa isang tiyak na mensahe, halimbawa, "lumabas" , naantala ang cycle, at magtatapos ang programa. Head Seven: Mas maganda ang multi-user. Maganda ang katotohanang naririnig tayo ng server, pero mas maganda kung makakausap natin ang isang tao na katulad natin. Ilakip ko ang lahat ng mga mapagkukunan sa dulo ng artikulo, kaya dito ipapakita ko hindi palaging malaki, ngunit mahalagang mga piraso ng code na gagawing posible, kung ginamit nang tama, upang bumuo ng isang multi-user na chat. Kaya, gusto naming makipag-ugnayan sa ibang kliyente sa pamamagitan ng server. Paano ito gagawin? Malinaw, dahil ang programa ng kliyente ay may sariling pamamaraan main, nangangahulugan ito na maaari itong ilunsad nang hiwalay mula sa server at kahanay sa iba pang mga kliyente. Ano ang ibinibigay nito sa atin? Sa anumang paraan, kinakailangan na sa bawat bagong koneksyon ang server ay hindi agad pumunta sa komunikasyon, ngunit isinulat ang koneksyon na ito sa ilang uri ng listahan at nagpapatuloy na maghintay para sa isang bagong koneksyon, at ang ilang uri ng auxiliary na serbisyo ay nakikibahagi sa komunikasyon sa isang tiyak na kliyente. At ang mga kliyente ay dapat sumulat sa server at maghintay para sa isang tugon nang nakapag-iisa sa bawat isa. Ang mga thread ay dumating upang iligtas. Sabihin nating mayroon kaming isang klase na responsable para sa pag-alala ng mga bagong koneksyon: Dapat itong may sumusunod na tinukoy:
  1. Numero ng port.
  2. Ang listahan kung saan isinusulat nito ang bagong koneksyon.
  3. At ServerSocket, sa isang solong (!) na kopya.
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();
        }
    }
}
Okay, ngayon ang bawat muling ginawang socket ay hindi mawawala, ngunit maiimbak sa server. Dagdag pa. Ang bawat customer ay nangangailangan ng isang tao na makinig. Gumawa tayo ng thread na may mga function ng server mula sa huling kabanata.
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) {}
    }
}
Kaya, sa constructor ng thread ng server, dapat magsimula ang isang socket kung saan makikipag-ugnayan ang thread sa isang partikular na kliyente. Gayundin ang mga thread ng I/O, at lahat ng iba pa na kailangan mo upang simulan ang isang thread nang direkta mula sa constructor. Okay, ngunit ano ang mangyayari kapag nagbasa ang thread ng server ng mensahe mula sa kliyente? Ibalik lang sa iyong kliyente? Hindi masyadong epektibo. Gumagawa kami ng isang multi-user na chat, kaya kailangan namin ang bawat konektadong kliyente upang matanggap ang isinulat ng isang tao. Kailangan mong gamitin ang listahan ng lahat ng mga thread ng server na nauugnay sa kanilang mga kliyente at ipadala ang bawat mensaheng ipinadala sa isang partikular na thread upang maipadala ito sa kliyente nito:
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) {}
}
Ngayon malalaman ng lahat ng kliyente kung ano ang sinabi ng isa sa kanila! Kung hindi mo gustong ipadala ang mensahe sa taong nagpadala nito (alam na niya kung ano ang isinulat niya!), Sa simpleng pag-ulit sa mga thread, tukuyin na kapag nagpoproseso ng isang bagay, thislilipat ang loop sa susunod na elemento nang hindi gumaganap anumang aksyon dito. O, kung gusto mo, magpadala ng mensahe sa kliyente na nagsasaad na matagumpay na natanggap at naipadala ang mensahe. Ang lahat ay malinaw sa server ngayon. Lumipat tayo sa kliyente, o sa halip sa mga kliyente! Ang lahat ay pareho doon, sa pamamagitan ng pagkakatulad sa kliyente mula sa huling kabanata, kapag lumilikha lamang ng isang pagkakataon na kailangan mo, tulad ng ipinakita sa kabanatang ito kasama ang server, upang lumikha ng lahat ng kailangan sa tagabuo. Ngunit paano kung, kapag lumilikha ng isang kliyente, wala pa siyang oras na magpasok ng anuman, ngunit mayroon nang ipinadala sa kanya? (Halimbawa, ang kasaysayan ng pagsusulatan ng mga nakakonekta na sa chat bago siya). Kaya't ang mga siklo kung saan ipoproseso ang mga ipinadalang mensahe ay dapat na ihiwalay sa mga kung saan binabasa ang mga mensahe mula sa console at ipinadala sa server para sa pagpapasa sa iba. Ang mga thread ay muling sumagip. Walang punto sa paglikha ng isang kliyente bilang isang thread. Ito ay mas maginhawa upang gumawa ng isang thread na may isang loop sa run method na nagbabasa ng mga mensahe, at gayundin, sa pamamagitan ng pagkakatulad, ay nagsusulat:
// 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) {

            }

        }
    }
}
Sa client constructor kailangan mo lang simulan ang mga thread na ito. Paano maayos na isara ang mga mapagkukunan ng kliyente kung gusto niyang umalis? Kailangan ko bang isara ang mga mapagkukunan ng thread ng server? Upang gawin ito, malamang na kailangan mong lumikha ng isang hiwalay na paraan na tinatawag kapag lumabas sa loop ng mensahe. Doon ay kakailanganin mong isara ang socket at I/O stream. Ang parehong signal ng pagtatapos ng session para sa isang partikular na kliyente ay dapat ipadala sa thread ng server nito, na dapat gawin ang parehong sa socket nito at alisin ang sarili nito mula sa listahan ng mga thread sa pangunahing klase ng server. Head Eight: Walang limitasyon sa pagiging perpekto Maaari kang walang katapusang mag-imbento ng mga bagong feature para mapabuti ang iyong proyekto. Ngunit ano nga ba ang dapat ilipat sa isang bagong konektadong kliyente? Sa tingin ko ang huling sampung pangyayari ay nangyari bago siya dumating. Upang gawin ito, kailangan mong lumikha ng isang klase kung saan ang huling aksyon sa anumang thread ng server ay ipapasok sa ipinahayag na listahan, at kung ang listahan ay puno na (iyon ay, mayroon nang 10), tanggalin ang una at idagdag ang huling dumating. Upang ang mga nilalaman ng listahang ito ay matanggap ng isang bagong koneksyon, kapag lumilikha ng isang thread ng server, sa output stream, kailangan mong ipadala ang mga ito sa kliyente. Paano ito gagawin? Halimbawa, tulad nito:
public void printStory(BufferedWriter writer) {
// ...
}
Ang thread ng server ay nakagawa na ng mga stream at maaaring pumasa sa output stream bilang argumento. Susunod, kailangan mo lamang ipasa ang lahat ng kailangang ilipat sa bagong kliyente sa isang ikot ng paghahanap. Konklusyon: Ito ay mga pangunahing kaalaman lamang, at malamang na ang arkitektura ng chat na ito ay hindi gagana kapag gumagawa ng isang tunay na application. Ang program na ito ay nilikha para sa mga layuning pang-edukasyon at sa batayan nito ay ipinakita ko kung paano mo magagawang makipag-usap ang kliyente sa server (at kabaliktaran), kung paano ito gagawin para sa ilang mga koneksyon, at, siyempre, kung paano ito nakaayos sa mga socket. Ang mga mapagkukunan ay muling inayos sa ibaba, at ang source code ng program na sinusuri ay nakalakip din. Ito ang aking unang karanasan sa pagsulat ng isang artikulo) Salamat sa iyong pansin :)
  1. Pag-iisip sa Java Enterprise, ni Bruce Eckel et. Sinabi ni Al. 2003
  2. Java 8, Ang Kumpletong Gabay, Herbert Schildt, ika-9 na edisyon, 2017 (Kabanata 22)
  3. Socket programming sa Java na artikulo tungkol sa mga socket
  4. Socket sa opisyal na dokumentasyon
  5. ServerSocket sa opisyal na dokumentasyon
  6. mga mapagkukunan sa GitHub
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION