JavaRush /Java блогу /Random-KY /Socket жана ServerSocket класстары же “Салам, сервер? Мен...
Sergey Simonov
Деңгээл
Санкт-Петербург

Socket жана ServerSocket класстары же “Салам, сервер? Мени угуп жатасыңбы?"

Группада жарыяланган
Киришүү: «Столдун үстүндө компьютер бар болчу, анын артында codeдор бар болчу...» Socket жана ServerSocket класстары же “Салам, server?  Мени угуп жатасыңбы?"  - 1 Бир жолу менин классташтарымдын бири Java тorн изилдөөнүн кезектеги жыйынтыгын жаңы программанын скриншоту түрүндө жарыялаган. Бул программа көп колдонуучу чат болчу. Ал убакта мен бул тилде программалоону өздөштүрүү боюнча өз саякатымды жаңыдан баштап жаткан элем, бирок мен өзүмө “мен муну каалайм!” деп сөзсүз түрдө белгилеп койгом. Убакыт өтүп, программалоо боюнча бorмимди тереңдетүүнүн алкагында кийинки долбоордун үстүндө иштеп бүтүп, ошол окуяны эстеп, убакыт келди деп чечтим. Эмнегедир мен бул теманы кызыккандыктан казып баштадым, бирок менин негизги Java окуу китебимде (бул Шилдттин толук колдонмосу болгон) java.net пакети үчүн 20 гана барак берилген. Бул түшүнүктүү - китеп буга чейин абдан чоң. Негизги класстардын методдорунун жана конструкторлорунун tableлары бар болчу, бирок ушуну менен бүттү. Кийинки кадам, албетте, кудуреттүү Google: бир эле нерсе берилген сансыз ар кандай макалалар - розеткалар жөнүндө эки же үч сөз жана даяр мисал. Классикалык ыкма (жок дегенде менин окуу стorмде) бул, адегенде жумуш үчүн куралдардан мага эмне керек экенин, алар эмне экенин, алар эмне үчүн керек экенин түшүнүү, андан кийин гана маселенин чечими ачык болбосо, анда гайкаларды жана болтторду бурап, даяр тизмелерди. Бирок мен эмне экенин түшүнүп, акыры көп колдонуучу чатын жаздым. Сыртынан караганда, мындай болуп чыкты: Socket жана ServerSocket класстары же “Салам, server?  Мени угуп жатасыңбы?"  - 2Бул жерде мен сизге чат дизайнынын мисалында Java розеткаларынын негизиндеги кардар-serverдик тиркемелердин негиздери жөнүндө түшүнүк берүүгө аракет кылам. Javarash курсунда сиз баарлашасыз. Бул такыр башка деңгээлде болот, кооз, чоң, көп функциялуу. Бирок, биринчи кезекте, ар дайым пайдубалын тургузуу керек, ошондуктан бул жерде биз мындай бөлүмдүн негизинде эмне экенин аныктап алышыбыз керек. (Эгер кандайдыр бир кемчorктерди же каталарды тапсаңыз, PM же макаланын астына комментарийге жазыңыз). баштайлы. Биринчи башчысы: "Бул үй..." Тармак байланышы server менен бир кардар ортосунда кандай болорун түшүндүрүү үчүн, көп батирлүү үйдүн классикалык мисалын алалы. Кардар кандайдыр бир жол менен белгилүү бир server менен байланыш түзүшү керек дейли. Издөөчү издөө an objectи жөнүндө эмнени бorши керек? Ооба, дареги. Сервер булуттагы сыйкырдуу нерсе эмес, ошондуктан ал белгилүү бир машинада жайгашуусу керек. Үйгө окшоштуруп, эки макулдашылган тараптын жолугушуусу өтүшү керек. Ал эми көп кабаттуу үйдөн бири-бирин табуу үчүн имараттын бир дареги жетишсиз, жолугушуу боло турган батирдин номерин көрсөтүү керек. Ошо сыяктуу эле, бир компьютерде бир эле учурда бир нече server болушу мүмкүн жана кардар белгилүү бир server менен байланышуусу үчүн, ал туташуу боло турган порт номерин да көрсөтүүсү керек. Ошентип, дарек жана порт номери. Дарек Интернет мейкиндигинде машинанын идентификаторун билдирет. Бул домендик аталыш болушу мүмкүн, мисалы, "javarush.ru" , же кадимки IP. Порт- белгилүү бир розетка менен байланышкан уникалдуу номер (бул термин кийинчерээк талкууланат), башкача айтканда, аны менен байланышуу үчүн колдонулушу үчүн белгилүү бир кызмат ээлейт. Ошентип, биринин (serverдин) аймагында экиден кем эмес an objectилердин жолугушуусу үчүн аймактын (serverдин) ээси андагы (автомобильде) белгилүү бир батирди (портту) ээлеши керек, ал эми экинчиси жолугушуу ордун бorп туруп табышы керек. үйдүн дареги (домен же IP ), жана батирдин номери (порт). Экинчи башчысы: Socket менен таанышуу Тармакта иштөөгө байланыштуу түшүнүктөрдүн жана терминдердин ичинен эң маанилүүсү Socket. Ал байланыш пайда болгон чекитти билдирет. Жөнөкөй сөз менен айтканда, розетка тармактагы эки программаны бириктирет. Класс Socketрозетка идеясын ишке ашырат. Кардар менен server өзүнүн киргизүү/чыгарма каналдары аркылуу байланышат: Socket жана ServerSocket класстары же “Салам, server?  Мени угуп жатасыңбы?"  - 3 Бул класс кардар тарапта жарыяланып, server байланыш сигналын алуу менен аны кайра жаратат. Мына ушундай онлайн байланыш иштейт. Баштоо үчүн, бул жерде мүмкүн болгон класс конструкторлору Socket:
Socket(String Name_хоста, int порт) throws UnknownHostException, IOException
Socket(InetAddress IP-address, int порт) throws UnknownHostException
"хост_аты" - белгилүү бир тармак түйүнүн, IP дарегин билдирет. Эгерде розетка классы аны чыныгы, учурдагы дарекке айландыра албаса, анда өзгөчөлүк ыргытылат UnknownHostException. Порт бул порт. Эгерде 0 порт номери катары көрсөтүлсө, система өзү эркин портту бөлүп берет. Байланыш үзүлүп калса, өзгөчө жагдай да болушу мүмкүн IOException. Белгилей кетчү нерсе, экинчи конструктордогу дарек түрү InetAddress. Бул жардамга келет, мисалы, сиз дарек катары домен атын көрсөтүү керек болгондо. Ошондой эле, домен бир нече IP даректерди билдирсе, InetAddressалардын массивдерин алуу үчүн аларды колдоно аласыз. Бирок, ал IP менен да иштейт. Сиз ошондой эле хосттун атын, IP дарегин түзгөн byte массивин ж.б. ала аласыз. Биз ага дагы бир аз токтолобуз, бирок толук маалымат алуу үчүн расмий documentтерге өтүшүңүз керек. Түрдөгү an object инициализацияланганда Socket, ал таандык болгон кардар тармакка белгилүү бир дарек жана порт номери боюнча serverге туташкысы келгенин жарыялайт. Төмөндө класстын эң көп колдонулган ыкмалары келтирилген Socket: InetAddress getInetAddress()– розетка жөнүндө маалыматтарды камтыган an objectти кайтарат. Эгерде розетка туташтырылбаса - null int getPort()- serverге туташуу болгон портту кайтарат int getLocalPort()- розетка байланган портту кайтарат. Чындыгында, кардар менен server бир портто "байланышса" болот, бирок алар туташкан порттор такыр башка болушу мүмкүн boolean isConnected()- байланыш түзүлсө "чындыкты" кайтарат void connect(SocketAddress address)- жаңы туташууну көрсөтөт boolean isClosed()- розетка жабык болсо, чындыкты кайтарат. boolean isBound()- чындыкты кайтарат, эгерде розетка чындыгында дарекке байланган болсо, класс Socketинтерфейсти ишке ашырат AutoCloseable, ошондуктан аны try-with-resources. Бирок, сиз классикалык жол менен розеткаларды жабууга болот, Close(). Үчүнчү башкы: жана бул ServerSocket Келгиле, биз класс түрүндө Socket, кардар тарабында байланыш өтүнүчүн жарыяладык дейли. Сервер биздин каалообузду кантип табат? Бул үчүн serverде класс сыяктуу класс ServerSocketжана анда accept() ыкмасы бар. Анын конструкторлору төмөндө келтирилген:
ServerSocket() throws IOException
ServerSocket(int порт) throws IOException
ServerSocket(int порт, int максимум_подключений) throws IOException
ServerSocket(int порт, int максимум_подключений, InetAddress локальный_address) throws IOException
Декларациялоодо ServerSocket байланыш дарегин көрсөтүүнүн кереги жок, анткени байланыш serverдик машинада ишке ашат. Көп каналдуу хост менен гана server розеткасынын кайсы IP менен байланышы бар экенин көрсөтүшүңүз керек. Head Three.One: Жок деп айткан server Программаны керектүүдөн көбүрөөк ресурстар менен камсыз кылуу кымбат жана негизсиз болгондуктан, конструктордо ServerSocketсизден иштөө учурунда server кабыл алган максималдуу байланыштарды жарыялоону суранышат. Эгерде ал көрсөтүлбөсө, анда демейки боюнча бул сан 50гө барабар болуп эсептелет. Ооба, теориялык жактан ServerSocketбул server үчүн гана бир эле розетка деп болжолдоого болот. Бирок ал класска караганда такыр башка роль ойнойт Socket. Бул байланыш түзүү стадиясында гана керек. Түр an objectин түзүп, ServerSocketкимдир бирөө serverге кошулууну каалап жатканын бorшиңиз керек. accept() ыкмасы бул жерде туташтырылган. Максат кимдир бирөө ага туташкысы келгенге чейин күтөт жана бул болгондо типтеги an objectти Socket, башкача айтканда, кайра түзүлгөн кардар розеткасын кайтарат. Эми server тарапта кардар розеткасы түзүлгөндөн кийин, эки тараптуу байланыш башталышы мүмкүн. SocketКардар тарабында типтеги an objectти түзүү жана аны ServerSocketserver тарабын колдонуу менен кайра түзүү - туташуу үчүн минималдуу талап кылынат. Төртүнчү башчы: Аяз атага кат Кардар Вопрос: менен server кантип байланышат? Ответ:I/O агымдары аркылуу. Бизде эмне бар? Сервердин дареги жана кардардын порт номери бар розетка жана ошол эле нерсе, server тарапта accept() аркылуу. Ошентип, алар розетка аркылуу байланышат деп болжолдоо жөндүү. InputStreamБул үчүн, агымдарга жана OutputStreamтүрдөгү an objectтерге кирүү мүмкүнчүлүгүн берген эки ыкма бар Socket. Бул жерде алар:
InputStream getInputStream()
OutputStream getOutputStream()
Жылаңач byteтарды окуу жана жазуу анча натыйжалуу болбогондуктан, агымдарды буфердик же буфердик класстарга ороп койсо болот. Мисалы:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Байланыш эки багыттуу болушу үчүн мындай операциялар эки тараптан тең аткарылышы керек. Эми сиз бир нерсени in колдонуу менен жөнөтө аласыз, ал эми сырттан пайдаланып бир нерсени ала аласыз жана тескерисинче. Чынында, бул класстын иш жүзүндө жалгыз функциясы Socket. Ооба, flush() ыкмасы жөнүндө унутпаңыз BufferedWriter- ал буфердин мазмунун тазалайт. Бул аткарылбаса, маалымат берилбейт, демек, кабыл алынbyte. Кабыл алуучу жип да саптын аяктоо индикаторун күтөт – “\n”, антпесе билдирүү кабыл алынbyte, анткени чындыгында билдирүү бүтө элек жана толук эмес. Эгер бул сизге ыңгайсыз болуп көрүнсө, кабатыр болбоңуз, сиз классты ар дайым колдонсоңуз болот PrintWriter, аны жабуу керек, экинчи аргумент катары true көрсөтүңүз, андан кийин буферден чыгуу автоматтык түрдө ишке ашат:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
Ошондой эле, саптын соңун көрсөтүүнүн кереги жок; бул класс муну сиз үчүн жасайт. Бирок I/O саптары розетка жасай ала турган чекпи? Жок, сиз an objectтерди розетка агымдары аркылуу жөнөткүңүз келеби? Кудай учун. Аларды сериялаштырыңыз жана сиз барууга даярсыз:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Бешинчи башчысы: Интернет аркылуу реалдуу байланыш Чыныгы IP дареги менен чыныгы тармак аркылуу туташуу үчүн сизде толук кандуу server болушу керек, жана:
  1. Биздин келечектеги чат, коммуналдык катары, мындай жөндөмдөрү жок. Ал гана байланыш түзө алат жана билдирүүнү кабыл алат/жөнөтө алат. Башкача айтканда, анын чыныгы serverдик мүмкүнчүлүктөрү жок.
  2. Сокет маалыматтарын жана киргизүү/чыгаруу агымдарын гана камтыган биздин server чыныгы WEB же FTP serverи катары иштей алbyte, ошондо гана биз Интернет аркылуу туташа албайбыз.
Мындан тышкары, биз программаны жаңыдан иштеп чыгууну баштайбыз, демек, ал дароо реалдуу тармак менен иштөө үчүн туруктуу эмес, ошондуктан биз байланыш дареги катары жергorктүү хостту колдонобуз. Башкача айтканда, теориялык жактан кардар менен server розеткадан башка эч кандай жол менен туташа алbyte, бирок программаны оңдоо үчүн алар тармак аркылуу реалдуу байланышсыз бир эле машинада болушат. Конструктордо Socketдарек локалдык экенин көрсөтүү үчүн 2 жол бар:
  1. Дарек аргументи катары "localhost" деп жазыңыз, бул жергorктүү такты билдирет. Бул үчүн "127.0.0.1" да ылайыктуу - бул жөн гана санариптик форма.
  2. InetAddress колдонуу:
    1. InetAddress.getByName(null)- жергorктүү хостко нөл пункттары
    2. InetAddress.getByName("localhost")
    3. InetAddress.getByName("127.0.0.1")
Жөнөкөйлүк үчүн биз String түрүндөгү "localhost" колдонобуз. Бирок башка бардык варианттар да ишке ашат. Башчы алты: Сүйлөшүү убактысы келди Ошентип, бизде server менен сүйлөшүү сессиясын ишке ашыруу үчүн керектүү нерселердин баары бар. Болгону аны чогултуу гана калды: Төмөнкү листинг кардар serverге кантип туташып, ага бир билдирүү жөнөтөрүн көрсөтөт жана 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);
        }

    }
}
Албетте, адегенде serverди башташ керек, анткени аны туташтыра турган эч нерсе жок болсо, кардар ишке киргенде эмнеге туташат? :) Чыгуу мындай болот: /* Сиз бир нерсе айткыңыз келдиби? Аны бул жерге киргизиңиз: Саламатсызбы, server? Мени угуп жатасыңбы? Салам, бул server! Мен ырастайм, сиз жаздыңыз: Саламатсызбы, server? Мени угуп жатасыңбы? Кардар жабылды... */ Уррай! Биз serverди кардар менен баарлашууга үйрөттүк! Байланыш эки репликада эмес, каалаганыңызча болушу үчүн, жиптерди окуу жана жазууну бир аз (чыныгы) циклге ороп, чыгуу үчүн белгилүү бир билдирүүгө ылайык, мисалы, "чыгуу" деп көрсөтүңүз. , цикл үзгүлтүккө учурап, программа бүтмөк. Жетинчи башчы: Көп колдонуучу жакшыраак.Сервердин бизди угушу жакшы, бирок өзүбүздүн түрдөгү адам менен баарлашсак жакшы болмок. Мен макаланын аягында бардык булактарды тиркейм, ошондуктан бул жерде мен ар дайым чоң эмес, бирок туура колдонулса, көп колдонуучу чатын түзүүгө мүмкүндүк берүүчү codeдун маанилүү бөлүктөрүн көрсөтөм. Ошентип, биз server аркылуу башка кардар менен баарлашууну каалайбыз. Муну кандай жасаш керек? Албетте, кардар программасынын өзүнүн ыкмасы болгондуктан main, аны serverден өзүнчө жана башка кардарлар менен параллелдүү ишке киргизүүгө болот. Бул бизге эмне берет? Кандайдыр бир жол менен, ар бир жаңы туташуу менен server байланышка дароо өтпөстөн, бул байланышты кандайдыр бир тизмеге жазып, жаңы туташууну күтүүгө киришиши керек, ал эми кандайдыр бир жардамчы кызмат белгилүү бир байланыш менен алектенет. кардар. Ал эми кардарлар serverге жазып, бири-биринен көз карандысыз жооп күтүшү керек. Жиптер жардамга келет. Бизде жаңы байланыштарды эстеп калуу үчүн жооптуу класс бар дейли: Анда төмөнкүлөр көрсөтүлүшү керек:
  1. Порт номери.
  2. Жаңы байланышты жаза турган тизме.
  3. Жана ServerSocket, бир (!) нускада.
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();
        }
    }
}
Макул, эми ар бир кайра түзүлгөн розетка жоголбойт, бирок serverде сакталат. Андан ары. Ар бир кардар уга турган бирөө керек. Акыркы бөлүмдөн serverдин функциялары менен жип түзөлү.
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) {}
    }
}
Ошентип, server жипинин конструкторунда розетка инициализацияланышы керек, ал аркылуу жип белгилүү бир кардар менен байланышат. Ошондой эле киргизүү/чыгаруу жиптери, ошондой эле жипти түз конструктордон баштоо үчүн керек болгон нерселердин бардыгы. Макул, бирок server жип кардардын билдирүүсүн окуганда эмне болот? Кардарыңызга гана кайра жөнөтөсүзбү? Өтө эффективдүү эмес. Биз көп колдонуучу чатын түзүп жатабыз, андыктан ар бир туташкан кардар бир адамдын жазганын алуу үчүн керек. Сиз алардын кардарлары менен байланышкан бардык server жиптеринин тизмесин колдонушуңуз керек жана ар бир билдирүүнү белгилүү бир жипке жөнөтүшүңүз керек, ал аны өзүнүн кардарына жөнөтөт:
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) {}
}
Эми бардык кардарлар алардын бири эмне дегенин бorшет! Эгер сиз билдирүү жөнөткөн адамга жөнөтүлүшүн каалабасаңыз (ал эмне жазганын билет!), жөн гана жиптер аркылуу итерациялоодо, an objectти иштетип жатканда цикл thisкийинки элементке өтөөрүн белгилеңиз. ал боюнча кандайдыр бир иш-аракеттер. Же болбосо, эгер кааласаңыз, кардарга билдирүү ийгorктүү кабыл алынып, жөнөтүлгөнү тууралуу билдирүү жөнөтүңүз. Азыр serverде баары түшүнүктүү. Кардарга, тагыраак айтканда, кардарларга өтөлү! Бул жерде баары бирдей, акыркы бөлүмдөгү кардар менен окшош, инстанцияны түзүүдө гана, бул бөлүмдө server менен көрсөтүлгөндөй, конструктордо зарыл болгон нерселердин бардыгын түзүү керек. Бирок, кардар түзүп жатканда, ал эч нерсе киргизгенге үлгүрө элек болсо, бирок ага бир нерсе жөнөтүлгөн болсочу? (Мисалы, ага чейин чатка кошулгандардын кат алышуу тарыхы). Ошентип, жөнөтүлгөн билдирүүлөр иштетиле турган циклдер консолдон кабарлар окулуп, башкаларга жөнөтүү үчүн serverге жөнөтүлгөн циклдерден бөлүнүшү керек. Жиптер кайрадан жардамга келет. Жип катары кардарды түзүүнүн эч кандай мааниси жок. Кабарларды окуй турган, ошондой эле аналогия боюнча мындай деп жаза турган run методунда цикл менен жип жасоо ыңгайлуураак.
// 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) {

            }

        }
    }
}
Кардардын конструкторунда сиз жөн гана бул жиптерди башташыңыз керек. Ал кеткиси келсе, кардардын ресурстарын кантип жабуу керек? Мен server жип ресурстарын жабуу керекпи? Бул үчүн, сиз, кыязы, билдирүү циклинен чыкканда чакырылган өзүнчө ыкманы түзүшүңүз керек болот. Ал жерде розетка жана киргизүү/чыгаруу агымдарын жабуу керек болот. Белгилүү бир кардар үчүн ошол эле сеанстын аяктоо сигналы анын server жипине жөнөтүлүшү керек, ал өзүнүн розеткасына да ушундай кылышы керек жана негизги server классындагы жиптердин тизмесинен өзүн алып салышы керек. Сегиз башчы: Кемчorксиздиктин чеги жок. Долбооруңузду өркүндөтүү үчүн жаңы функцияларды ойлоп таба аласыз. Бирок жаңы кошулган кардарга эмнени өткөрүп берүү керек? Акыркы он окуя ал келгенге чейин болгон деп ойлойм. Бул үчүн, сиз классты түзүшүңүз керек, анда каалаган server жиптери менен акыркы аракет жарыяланган тизмеге киргизилет жана тизме толгон болсо (б.а. 10 бар), биринчисин жок кылып, кошуңуз. акыркы келген. Бул тизменин мазмуну жаңы туташуу аркылуу кабыл алынышы үчүн, serverдик жипти түзүүдө чыгаруу агымында сиз аларды кардарга жөнөтүшүңүз керек. Муну кандай жасаш керек? Мисалы, бул сыяктуу:
public void printStory(BufferedWriter writer) {
// ...
}
Сервер агымы мурунтан эле агымдарды жараткан жана чыгуу агымын аргумент катары өткөрө алат. Андан кийин, сиз жөн гана издөө циклинде жаңы кардарга өткөрүлүшү керек болгон нерселердин бардыгын өткөрүп беришиңиз керек. Корутунду: Бул жөн гана негиздер жана бул чат архитектурасы чыныгы тиркемени түзүүдө иштебейт. Бул программа бorм берүү максатында түзүлгөн жана анын негизинде мен кардарды server менен кантип байланыштырууга болорун (жана тескерисинче), муну бир нече туташуулар үчүн кантип жасоо керектигин жана, албетте, бул розеткаларда кантип уюштурулганын көрсөттүм. Төмөндө булактар ​​кайра иреттелген жана талданып жаткан программанын баштапкы codeу да тиркелет. Бул менин макала жазуудагы биринчи тажрыйбам) Көңүл бурганыңыз үчүн рахмат :)
  1. Java Enterprise менен ойлонуу, Брюс Эккел et. Ал. 2003
  2. Java 8, Толук колдонмо, Герберт Шилдт, 9-басылышы, 2017 (22-бөлүм)
  3. Java тorнде розеткаларды программалоо розеткалар жөнүндө макала
  4. Расмий documentтерде розетка
  5. Расмий documentтерде ServerSocket
  6. GitHub булактары
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION