Java как сделать сервер

Первое знакомство с протоколом HTTP через написание простейшего Web сервера на Java

Думаю что не будет преувеличением утверждать, что знание и понимание сути протокола HTTP необходимо любому, кто решил сколь-нибудь серьезно заняться любым из направлений современной Web разработки. Мой личный опыт говорит о том, что понимание это приходит не сразу. Стыдно сказать, что были времена, когда слова GET и POST были для меня сродни магическим заклинаниям, а о существовании PUT, PATCH и DELETE я даже не подозревал.

Несколько месяцев назад помимо собственно разработки я занялся также преподаванием, и возник вопрос о том, как проще и понятнее рассказать о сути протокола HTTP будущим Java разработчикам. После нескольких дней возни и ряда неудачных попыток сделать презентацию возникла идея, а почему бы не написать простейший HTTP сервер на Java, потому как ни что так хорошо не объясняет суть протокола, как его простейшая, но работающая реализация.

Как оказалось сделать это совсем не сложно. Ниже привожу код, которого будет достаточно для корректного взаимодействия с любым браузером! Все что нам понадобится это ServerSocket и немного стандартного ввода-вывода.

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; public class HttpServer < public static void main(String[] args) < try (ServerSocket serverSocket = new ServerSocket(8080)) < System.out.println("Server started!"); while (true) < // ожидаем подключения Socket socket = serverSocket.accept(); System.out.println("Client connected!"); // для подключившегося клиента открываем потоки // чтения и записи try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)); PrintWriter output = new PrintWriter(socket.getOutputStream())) < // ждем первой строки запроса while (!input.ready()) ; // считываем и печатаем все что было отправлено клиентом System.out.println(); while (input.ready()) < System.out.println(input.readLine()); >// отправляем ответ output.println("HTTP/1.1 200 OK"); output.println("Content-Type: text/html; charset=utf-8"); output.println(); output.println("

Привет всем!

"); output.flush(); // по окончанию выполнения блока try-with-resources потоки, // а вместе с ними и соединение будут закрыты System.out.println("Client disconnected!"); > > > catch (IOException ex) < ex.printStackTrace(); >> >

Пробуем запустить этот код. Стоит отметить, что порт, для которого создается ServerSocket должен быть свободным. Если указанный порт занят, то нужно или его освободить, или использовать другой свободный порт.

После запуска этого кода идем в окно браузера и набираем в адресной строке http://localhost:8080/ . Если все прошло удачно, то в окне браузера мы увидим текст «Привет всем», а в логе сервера текст, подобный приведенному ниже:

Server started! Client connected! GET / HTTP/1.1 Host: localhost:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,he;q=0.6,de;q=0.5,cs;q=0.4 Cookie: _ga=GA1.1.1849608036.1549463927; portainer.pagination_containers=100; _gid=GA1.1.80775985.1550669456; If-Modified-Since: Sat, 05 Jan 2019 12:10:16 GMT Client disconnected!

Каждый раз, когда мы что-то вводим в адресную строку браузера и нажимаем Enter не происходит ничего иного, как отправка текста, начинающегося словом GET и заканчивающегося переводом строки. После слова GET через пробел следует путь к запрашиваемому документу на сервере. Попробуйте ввести в браузере http://localhost:8080/something и посмотреть, как изменится текст запроса в логе.

Читайте также:  Common java program errors

В строках запроса, начиная со второй находятся т.н. заголовки при помощи которых осуществляется передача серверу информации о настройках клиента. Каждая строка заголовка имеет формат [имя заголовка] : [значение]; [значение]; . [значение] .

После того, как текст запроса полностью прочитан сервером, мы отправляем ему простейший ответ, структура которого довольно проста и аналогична структуре запроса. В первой строке версия протокола HTTP и код 200 OK, который сообщит браузеру о том, что запрос был успешно обработан (всем куда лучше знаком код 404, не правда ли 😉 ). Далее следует всего один заголовок Content-Type в котором передается информация о формате передаваемого документа (text/html) и его кодировке (charset=utf-8). После заголовка следует перевод строки (обязательное требование протокола HTTP) и собственно текст, который будет отображен в браузере.

На этом все! Разумеется это далеко не все, что нужно знать о протоколе HTTP и принципах разработки Web серверов, но мне бы не хотелось усложнять данный пример, т.к. главная его задача — продемонстрировать, простейшую коммуникацию по протоколу HTTP. В одном из следующих своих материалов постараюсь развить тему изучения протокола HTTP через его реализацию.

UPD. Гораздо более продвинутый пример подобного сервера можно найти в книге How Tomcat Works: A Guide to Developing Your Own Java Servlet Container by Paul Deck, Budi Kurniawan, глава 1 — Simple Web Server.

Источник

One of the most frequency used protocol in the whole Internet *

* In OSI model, layer 7 Every time you visit a website your web browser uses the HTTP protocol to communicate with web server and fetch the page’s content. Also, when you are implementing backend app and you have to communicate with other backend app — 80% (or more) of cases you will use the HTTP. Long story short — when you want to be a good software developer, you have to know how the HTTP protocol works. And wiring the HTTP server is pretty good way to understood, I think.

What a web browser sends to the web server?

Alt Text

Good question. Of course, you can use «developer tools», let’s do it. Hmm. but what now? What exactly it means? We can see some URL, some method, some status, version (huh?), headers, and other stuff. Useful? Yes, but only to analyze the web app, when something is wrong. We still don’t know how HTTP works.

Читайте также:  Python удаление последнего символа строки

Wireshark, my old friend

Alt Text

The source of truth. Wireshark is application to analyze network traffic. You can use it to see each packet that is sent by your (or to your) PC. But to be honest — if you know how to use Wireshark — you probably know how HTTP and TCP works. It’s pretty advanced program.

You are right — the specification

Every good (I mean — used by more that 5 peoples) protocols should have specification. In this case it’s called RFC. But don’t lie — you will never read this, it’s too long — https://tools.ietf.org/html/rfc2616 .

Just run the server and test

Joke? No. Probably you have installed on your PC very powerful tool called netcat, it’s pretty advanced tool.
One of the netcat features is TCP server. You can run the netcat to listen on specific port and print every thing what it gets. Netcat is a command line app.

Netcat (nc), please, listen (-l) on port 8080 (-p 8080) and print everything (-v). Now open web browser and enter http://localhost:8080/ . Your browser will send the HTTP request to the server runned by netcat. Of course nc will print the whole request and ignore it, browser will wait for the response (will timeout soon). To kill nc press ctrl+c . So, finally, we have an HTTP request!

GET / HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: JSESSIONID=D3AF43EBFC0C9D92AD9C37823C4BB299 Upgrade-Insecure-Requests: 1 

HTTP request

It may be a little confusing. Maybe nc parses the request before printing? HTTP protocol should be complicated, where is the sequence of 0 and 1? There aren’t any. HTTP is really very simple text protocol. There is only one, little trap (I will explain it at the end of this section). We can split the request to the 4 main parts:

This is the main request. GET — this is the HTTP method. Probably you know there are a lot of methods.
GET means give me / — resource. / means default one.
When you will open localhost:8080/my_gf_nudes.html , the resource will be /my_gf_nudes.html HTTP/1.1 — HTTP version. There are few versions, 1.1 is commonly used.

Host. One server can host many domains, using this field, the browser says which domain it wants exactly

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: JSESSIONID=D3AF43EBFC0C9D92AD9C37823C4BB299 Upgrade-Insecure-Requests: 1 

Surprise — empty line. It means: end of the request. In general — empty line in HTTP means end of section.

The trap

Response

Ok. We have a request. How does response look like? Send a request to any server and see, there is nothing simpler.
On your laptop you can find another very useful tool — telnet . Using telenet you can open TCP connection, write something to server and print the response.
Try to do it yourself. Run telnet google.com 80 (80 is the default HTTP port) and type request manually (you know how it should look like). To close connection press ctrl+] than type quit . OK. We have a response.

HTTP/1.1 301 Moved Permanently 

HTTP/1.1 — version
301 — status code. I believe you are familiar with that
Moved Permanently — human-readable status code

Location: http://www.google.com/ Content-Type: text/html; charset=UTF-8 Date: Wed, 25 Mar 2020 18:53:12 GMT Expires: Fri, 24 Apr 2020 18:53:12 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 219 X-XSS-Protection: 0 X-Frame-Options: SAMEORIGIN 

Источник

Читайте также:  If variable starts with php

Простой HTTP-сервер на Java

Вы хотите реализовать HTTP-сервер , но не хотите рисковать написанием полноценного HTTP-сервера? Разработка HTTP-сервера с полной функциональностью не является тривиальной задачей. Но у Java есть решение этой проблемы. Java поддерживает встроенный HTTP-сервер. Просто написав 100 строк кода, мы можем разработать несколько приличный HTTP-сервер, который может обрабатывать запросы. Мы также можем использовать его для обработки других HTTP-команд.

HTTPServer

Java SDK предоставляет встроенный сервер под названием HttpServer . Этот класс относится к пакету com.sun.net .

Мы можем создать экземпляр сервера следующим образом:

HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 8001), 0); 

Приведенная выше строка создает экземпляр HTTPServer на локальном узле с номером порта 8001. Но есть еще один аргумент со значением 0. Это значение используется для обратной регистрации .

Очередь выполнения запросов

Когда сервер принимает запрос клиента, этот запрос сначала будет поставлен в очередь операционной системой. Позже он будет передан на сервер для обработки запроса. Все эти одновременные запросы будут поставлены в очередь операционной системой. Однако операционная система сама решит, сколько из этих запросов может быть поставлено в очередь в любой данный момент времени. Это значение представляет обратную регистрацию. В нашем примере это значение равно 0, что означает, что мы не ставим в очередь никаких запросов.

Код сервера

Мы собираемся разработать следующий HTTP-сервер:

server.createContext("/test", new MyHttpHandler()); server.setExecutor(threadPoolExecutor); server.start(); logger.info(" Server started on port 8001"); 

Мы создали контекст под названием test . Это не что иное, как корень контекста приложения. Второй параметр — это экземпляр обработчика, который будет обрабатывать HTTP-запросы. Мы рассмотрим этот класс в ближайшее время.

Мы можем использовать исполнителя пула потоков вместе с этим экземпляром сервера. В нашем случае мы создали пул из 10 потоков.

ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(10); 

С помощью всего трех-четырех строк кода мы создали HTTP-сервер с корневым контекстом, который прослушивает порт!

HTTPHandler

Это интерфейс с вызванным методом handle(..) . Давайте посмотрим на нашу реализацию этого интерфейса.

«). append(«Hello «) .append(requestParamValue) .append(«

Источник

Оцените статью