Java: сетевое взаимодействие
Основы сетевого взаимодействия Сетевой адрес (ipv4 8bit.8bit.8bit.8bit или доменное имя) Порт (до 65535) Протокол (стек протоколов)
Классы и пакеты Абстракции сетевого уровня: –пакет: java.net –классы: Socket, DatagramSocket, ServerSocket, MulticastSocket Ввод/вывод: –пакет: java.io –классы: InputStream, OutputStream, Reader, Writer
Сокеты TCP/IP – создание серверного сокета //Данные сервер может обрабатывать запросы только с одного клиента public static void main( String []args ){ try{ ServerSocket sock = new ServerSocket( 5555 ); Socket clientSocket; while( (clientSocket = sock.accept()) != null ){ System.out.println( "Client IP: " + clientSocket.getInetAddress() ); Scanner sc = new Scanner( clientSocket.getInputStream() ); while( sc.hasNext() ){ System.out.print( sc.next() + System.getProperty("line.separator") ); } System.out.println("Connection closed."); clientSocket.close(); } }catch( Exception exc ){ exc.printStackTrace(); } В качестве клиента можно использовать команду telnet: telnet localhost 5555
Сокеты TCP/IP – создание клиента public static void main( String []args ){ try{ Socket sock = new Socket( InetAddress.getLocalHost(), 5555 ); PrintStream ps = new PrintStream( sock.getOutputStream(), true ); for( int i = 0; i < 10; i++ ){ ps.println( "line #" + i ); Thread.sleep( 1000 ); } ps.close(); sock.close(); }catch( Exception exc ){ exc.printStackTrace(); }
Типовая схема взаимодействий #1
Типовая схема взаимодействий #2
Пример обмена данными - Сервер public static void main( String []args ){ try{ ServerSocket sock = new ServerSocket(); Socket clientSocket; sock.bind( new InetSocketAddress(InetAddress.getLocalHost(), 5555), 1 ); while( (clientSocket = sock.accept()) != null ){ System.out.println( "Client IP: " + clientSocket.getInetAddress() ); Scanner sc = new Scanner( clientSocket.getInputStream() ); PrintStream ps = new PrintStream( clientSocket.getOutputStream() ); while( sc.hasNext() ){ String cmd = sc.next(); if( cmd.equalsIgnoreCase("getData") ) ps.println("Data for " + clientSocket.getInetAddress() ); else if( cmd.equalsIgnoreCase("createData") ) System.out.println( "Data created" ); else if( cmd.equalsIgnoreCase("updateData") ) System.out.println( "Data updated" ); } ps.close(); sc.close(); System.out.println("Connection closed."); clientSocket.close(); } }catch( Exception exc ){ exc.printStackTrace(); } }
Пример обмена данными - Клиент public static void main( String []args ){ try{ Socket sock = new Socket( InetAddress.getLocalHost(), 5555 ); PrintStream ps = new PrintStream( sock.getOutputStream(), true ); Scanner sc = new Scanner( sock.getInputStream() ); ps.println( "createData" ); ps.println( "updateData" ); ps.println( "getData" ); System.out.println( sc.nextLine() ); sc.close(); ps.close(); sock.close(); }catch( Exception exc ){ exc.printStackTrace(); }
Сокеты UDP - сервер public static void main( String []args ){ try{ DatagramSocket sock = new DatagramSocket( 5556, InetAddress.getLocalHost() ); byte []buffer = new byte[ ]; DatagramPacket recvPacket = new DatagramPacket( buffer, buffer.length ); sock.receive( recvPacket ); System.out.println( "String len: " + buffer[0] ); System.out.println( "received: " + new String(buffer, 1, buffer[0]) ); sock.close(); }catch( Exception exc ){ exc.printStackTrace(); }
Сокеты UDP - клиент Признак успешного выполнения send отсутствует, нет гарантии доставки, в отличии от TCP-соединений (классы Socket/ServerSocket) public static void main( String []args ){ try{ DatagramSocket sock = new DatagramSocket( 5557, InetAddress.getLocalHost() ); String data2send = "UDP data packet"; byte []buffer = new byte[ data2send.length()+1 ]; buffer[0] = (byte)data2send.length(); System.arraycopy(data2send.getBytes(), 0, buffer, 1, data2send.getBytes().length ); DatagramPacket udpPacket = new DatagramPacket( buffer, buffer.length, InetAddress.getLocalHost(), 5556 ); sock.send( udpPacket ); sock.close(); }catch( Exception exc ){ exc.printStackTrace(); }
UDP – параллельная обработка запросов При получении пакета #2.1 ждать #2.2 нет возможности, т.к. потеряем пакеты с других клиентов; Обработка в отдельных потоках возможна только при дополнительном обмене пакетами типа Keep-alive.
Схема взаимодействия с комбинированной доставкой
UDP-сервер, настроенный на конкретного клиента //Параметры инициализации потока обработки //UDP-сообщений int CLIENT_PORT = 5557; InetAddress CLIENT_ADDR = InetAddress.getLocalHost(); DatagramSocket sock = new DatagramSocket( 5556, InetAddress.getLocalHost() ); byte []buffer = new byte[ ]; //Ожидание UDP-сообщения от конкретного клиента DatagramPacket recvPacket = new DatagramPacket( buffer, buffer.length, CLIENT_ADDR, CLIENT_PORT ); sock.receive( recvPacket );
Отправка широковещательных сообщений //Создается DatagramSocket, связанный с локальным адресом, порт //Сообщения отправляются на широковещательный адрес и порт public static void main( String []args ){ DatagramSocket mcastSocket = null; try{ int SERVER_PORT = 1111; int MCAST_PORT = 1212; InetAddress GROUP_ADDR = InetAddress.getByName( " " ); mcastSocket = new DatagramSocket( new InetSocketAddress( InetAddress.getLocalHost(), SERVER_PORT ) ); while( 2 == 2 ){ byte []buffer = ObjectSerializer.serialize("Hello world!"); DatagramPacket pack = new DatagramPacket( buffer, buffer.length, GROUP_ADDR, MCAST_PORT ); mcastSocket.send( pack ); Thread.sleep( 500 ); } }catch( Exception exc ){ exc.printStackTrace(); }finally{ try{ mcastSocket.close(); }catch( Exception closeExc ){} } }
Реализация клиента для получения широковещательных сообщений public static void main( String []args ){ try{ int MCAST_PORT = 1212; InetAddress GROUP_ADDR = InetAddress.getByName( " " ); MulticastSocket recvSock = new MulticastSocket( MCAST_PORT ); recvSock.joinGroup( GROUP_ADDR ); byte []buffer = new byte[ ]; DatagramPacket pack = new DatagramPacket( buffer, buffer.length ); recvSock.receive( pack ); String str = (String)ObjectSerializer.deserialize( buffer ); System.out.println("received: " + str ); recvSock.leaveGroup( mcastGroup ); recvSock.close(); }catch( Exception exc ){ exc.printStackTrace(); }
Справочная информация Диапазоны multicast-адресов: addresses/ addresses/ Спецификации протоколов Интернет (Requests for comments – RFC): Примеры: –описание SMTP: html –описание HTTP 1.1: html
Задание 1 Разработать программу-сервер для периодической отправки широковещательных сообщений, содержащих экземпляр класса: class BCastMessage implements java.io.Serializable{ //IP-адрес данного сервера public InetAddress serverAddress; //Порт, на который принимаются входящие TCP-соединения public int port; }
Задание 2 Разработать программу-клиента для получения списка доступных серверов. Задача программы – получение списка всех доступных серверов и фоновое заполнение списка в окне выбора сервера.
Задание 3 Добавить в программу из задания 1 обработку входящих TCP-соединений. Программа должна распознавать следующие команды: addMessage – добавление сообщения, данные, следующие за командой – текст сообщения, имя автора и дата отправки; ответ на команду не требуется; getMessages – сервер возвращает список (List) сообщений в выходной поток.
Задание 4 Добавить в программу-клиент из задания 2 окно (см. рис. на следующем слайде). При запуске программа должна отображать диалог со списком серверов. После выбора сервера показывается основное окно со списком сообщений. При выбор сервера, с ним устанавливается соединение по протоколу TCP и каждую секунду отправляется сообщение getMessages. Если пользователь нажимает кнопку «Отправить», происходит отправка сообщения с помощью команды addMessage.
Задание 4 – сетевое приложение