Курсов проект № 1 по “Интернет програмиране с Java”

 

Проект 1.1 – UDP Chat Client/Server:

Да се напишe клиент/сървър приложение на Java, което използвайки възможностите на пакета java.net дава възможност за комуникация между много потребители в локална мрежа. Изпращането и приемането на съобщения трябва да бъде реализирано с UDP сокети. Трябва да се напишат 2 програми – UDP Chat сървър и UDP Chat клиент. UDP Chat сървърът трябва да служи като централизирана точка, през която минават съобщенията, които са предназначени за всички потребители. UDP Chat клиентът трябва да е клиентско приложение, което си комуникира със UDP Chat сървъра и другите UDP Chat клиенти чрез UDP пакети.

UDP Chat клиентът представлява програма, която приема потребителски команди и ги изпълнява и същевременно приема изпратени до нея съобщения и ги отпечатва. Всеки потребител трябва да може да изпраща съобщения до всички останали или до конкретен друг потребител. Получаването и изпращането на съобщения трябва да става по UDP на порт 2002. Трябва да се реализират следните команди:

            SEND IP_ADDRESS MESSAGE – за изпращане на съобщение до конкретен потребител. Съобщението се изпраща чрез UDP пакет директно до зададения IP адрес на порт 2002 (не минава през сървъра).

            SEND * MESSAGE – за изпращане на съобщение до всички потребители. Тази команда, без изменение се изпраща чрез UDP пакет до UDP Chat сървъра на порт 2002. IP адресът на UDP Chat сървъра е предварително зададен като константа в клиентското приложение.

            QUIT – за изход от клиентската програма

При пристигане на съобщение от някой потребител то трябва да се извежда по подходящ начин. При стартиране на клиента той трябва да изпраща до UDP Chat сървъра команда “REGISTER <IP address>”, с което го уведомява, че се е включил в Chat-а. При изход, клиентът трябва да изпраща друга команда “UNREGISTER <IP address> до UDP Chat сървъра, за да го уведоми, че е излязъл от Chat-a. Във всеки един момент потребителят трябва да има възможност да изпълнява произволна от изброените по-горе команди.

UDP Chat сървърът представлява програма, която слуша на UDP порт 2002, приема команди и да ги изпълнява по подходящ начин. Командите са следните:

            REGISTER <IP address> – добавя IP адреса в списъка от клиентите (ако го няма вече там)

            UNREGISTER <IP address> – премахва IP адреса от списъка от клиентите (ако го има там)

SEND * MESSAGE – изпраща зададеното съобщение до всички клиенти чрез UDP пакет на порт 2002, като включва в него и IP адреса на изпращача, т.е. на този, от когото е получено, за да знае клиентът кой го е изпратил първоначално.

При пристигане на друга команда, тя се игнорира. UPD Chat сървърът трябва да поддържа списък от IP адресите на клиентите си, като при стартиране този списък е празен. Сървърът трябва да може да изпълнява много команди от различни потребители, дори ако са изпратени едновременно.

Пример: Нека UDP Chat сървърът е стартиран на адрес 192.168.0.31 и слуша на порт 2002. Alan и Bob са потребители в локална мрежа съответно с IP адреси 192.168.0.1 и 192.168.0.2. Двамата стартират вашия UDP Chat клиент. Съответно сървърът получава команди за регистрация на IP адреси 192.168.0.1 и 192.168.0.2.

Потребител Alan пише командите:

SEND * Hi all!

SEND 192.168.0.2 Hi Bob!

Първата команда се изпраща без изменение до сървъра (по UDP към 192.168.0.31:2002), а втората просто предизвиква изпращане на клиента 192.168.0.2 по UDP на порт 2002 съобщението “Hi Bob!”.

След това потребител Bob пише командите:

SEND 192.168.0.1 Hi Alan, I am pleased to chat with you!

SEND * Anybody for Counter Strike?

Те се обработва отново съгласно описанието на клиентското приложение.

След това Alan пише командите:

SEND 192.168.0.2 Bob, I don’t like this game. I have to work now.

SEND 192.168.0.2 Goodbye Bob.

SEND * Goodbye all.

QUIT

След това потребител Bob пише командите:

SEND * Ok. I am leaving. The game session will start at 11.30 pm. Bye all.

QUIT

Сървърът приема всички команди от вида SEND * MESSAGEи разпраща съобщенията до всички от списъка си с клиенти, като слага в тях някаква идентификация от кого са пристигнали. При излизане от Chat-а (с командата QUIT), сървърът получава и изпълнява команди за напускане на съответните клиенти и ги изтрива от списъците.

Ако всичко е протекло нормално, екранът на Alan в този момент трябва да изглежда по начин подобен на този:

Welcome to the UDP chat

SEND * Hi all!

Received message from 192.168.0.1: Hi all!

SEND 192.168.0.2 Hi Bob!

Received message from 192.168.0.2: Hi Alan, I am pleased to chat with you!

Received message from 192.168.0.2: Anybody for Counter Strike?

SEND 192.168.0.2 Bob, I don’t like this game. I have to work now.

SEND 192.168.0.2 Goodbye Bob.

SEND * Goodbye all.

Received message from 192.168.0.1: Goodbye all.

QUIT

Екранът на Bob в този момент трябва да изглежда по начин подобен на този:

Welcome to the UDP chat

Received message from 192.168.0.1: Hi all!

Received message from 192.168.0.1: Hi Bob!

SEND 192.168.0.1 Hi Alan, I am pleased to chat with you!

SEND * Anybody for Counter Strike?

Received message from 192.168.0.2: Anybody for Counter Strike?

Received message from 192.168.0.1: Bob, I don’t like this game. I have to work now.

Received message from 192.168.0.1: Goodbye Bob.

Received message from 192.168.0.1: Goodbye all.

SEND * Ok. I am leaving. The game session will start at 11.30 pm. Bye all.

Received message from 192.168.0.2: Ok. I am leaving. The game session will start at 11.30 pm. Bye all.

QUIT

 

Не е нужно да създавате графичен потребителски интерфейс. Достатъчно е да напишете конзолни приложения, които реализират описаната функционалност. Не е нужно да се грижите за синхронизация на конзолата (т.е. допустимо е докато пишете команда, съобщение, пристигнало от някъде, да се отпечата върху реда, в които пишете).

Забележка: В по-старите версии на настоящия документ проект 1.1 беше друг (Multicast Chat), но се наложи да бъде променен заради необходимостта от работеща локална мрежа за да се използват Multicast сокети. Заради невъзможността на повечето от вас да разработват проекта си на компютър, който е включен в локална мрежа, се наложи условието му да бъде променено. Моля всички да работят по новото условие (UDP Chat Client/Server)!


Проект 1.2 – Simple Web Server:

Да се напише програма на Java, която използвайки възможностите на пакета java.net реализира прост Web-сървър, който обслужва TCP заявките на порт 80. Сървърът трябва да може да работи с няколко потребителя едновременно и да отговаря на следната команда:

GET [ресурс] HTTP/x.x – за извличане на файл от сървъра съгласно HTTP протокола

При заявка за достъп до директория на сървъра (например при поискване на /docs/), той трябва да връща динамично генериран HTML документ със списък от линкове към всички файлове и директории в съответната директория. При заявка за достъп до файл (например при поискване на /index.html), трябва да връща този файл. Ако файлът не съществува или не може да бъде отворен за четене, трябва да се връща грешка 404 съгласно HTTP протокола (виж примерите). Имената на ресурсите в GET-заявките могат да бъдат зададени както във вид на URL (например http://localhost/index.html), така и във вид на път и име до ресурса (например /welcome.gif). Ако името на един ресурс е зададено чрез URL, вашият сървър трябва да извлече от това URL само частта задаваща пътя и името на ресурса, като игнорира http:// частта и host-а. Вашият сървър трябва да приема за главна директория (Document root) някоя предварително фиксирана директория на от файловата система (например C:\DOCUMENT_ROOT). Тази директория e физическото съответствие във файловата система на главната виртуална директория в сървъра. Тази главна виртуална директория означаваме с “/”. В нашия пример ако потребителят поиска от сървъра файла /docs/inetjava/InetJava.doc, това съответства на физическия файл C:\DOCUMENT_ROOT\docs\inetjava\InetJava.doc, а ако поиска директорията /, това съответства на физическата директория C:\DOCUMENT_ROOT\ във файловата система на сървъра. На потребителя трябва да се дава достъп до всички файлове и поддиректории на Document root директорията и до никои други, т.е. разхождайки се по директориите, той трябва да не може да напусне главната виртуална директория.

            При команда, която не е GET, да се върне отговор:

HTTP/1.0 501 Not Implemented

MIME-Version: 1.0

Content-type: text/html

 

<html> Not implemented </html>

Не е нужно да създавате графичен потребителски интерфейс. Достатъчно е да напишете конзолно приложение, което реализира описаната функционалност. Можете да тествате вашето приложение със стандартен Web-браузър (например Internet Explorer).

За улеснение може да се счита, че в имената на файловете и директориите няма интервали и специални символи (като , , :, /, \ и подобни).

Пример: Web-браузерът (клиентското приложение) се свързва на порт 80 към вашия Simple Web Server и задава няколко-редова текстова заявка. Например:

GET http://localhost/index.html HTTP/1.1

Accept: */*

Accept-Language: bg

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

Host: localhost

Connection: Keep-Alive

Cache-Control: no-cache

 

Забележете, че последният ред на заявката е празен. Съгласно HTTP протокола този празен ред определя края на заявката. В края на първия ред е зададена версията на HTTP протокола която е използвана за формиране на заявката. Тя може да бъде както HTTP/1.1, така и HTTP/1.0. Независимо от тази версия вашият сървър трябва да връща отговорите си по протокол HTTP/1.0. Той трябва да отвори файла index.html, намиращ се в главната виртуална директория и да го върне на клиента в съответен отговор. Например:

HTTP/1.0 200 OK

MIME-Version: 1.0

Content-type: text/html

 

<html>

    <CENTER><H1>Welcome</H1></CENTER>

</html>

Забележете че, между заглавната част на отговора и самия документ има оставен празен ред. Съгласно HTTP протокола този празен ред разделя хедъра от данните в отговора на HTTP GET заявка.

Вашият Web-сървър трябва да задава в хедъра на отговора в полето Content-type различни стойности в зависимост от разширението на поискания файл:

text/html – за *.htm, *.html файлове

image/gif – за *.gif файлове

image/jpg – за *.jpg файлове

application/zip – за *.zip файлове

text/plain – за всички останали типове файлове (*.*)

Освен това в този хедър на HTTP отговора трябва да се включи още един ред: “MIME-Version: 1.0”, който задава с коя версия на MIME стандарта да се тълкува реда “Content type: ....

Пример 2:

Заявка (изпратена от клиента за извеждане на файловете от директория /nakov):

GET /nakov HTTP/1.1

Accept: */*

Host: localhost

Отговор (върнат от сървъра):

HTTP/1.0 200 OK

MIME-Version: 1.0

Content-type: text/html

 

<html>

    Directory listing of <a href="/nakov/">/nakov/</a> <br> <br>

    <a href="/nakov/InetJava.doc">/nakov/InetJava.doc</a> <br>

    <a href="/nakov/HTTP_protocol.zip">/nakov/HTTP_protocol.zip</a> <br>

    <a href="/nakov/JAVA_sockets.zip">/nakov/JAVA_sockets.zip</a> <br>

</html>

Вижда се, че съгласно спецификацията на вашия Web-сървър, той връща списък с линкове към файлове в зададената директория (когато тя съществува, т.е. има физическо съответствие във файловата система). Забележете, че ресурсът поискан с командата GET /nakov HTTP/1.1 е зададен не като URL, а като път и име на ресурс. Тази команда е еквивалентна на командата GET http://localhost/nakov HTTP/1.1 в рамките на вашия Web-сървър.

 

Пример 3:

Заявка за несъществуващ файл (изпратена от клиента):

GET http://localhost/nakov/index.html HTTP/1.1

Accept: */*

Host: localhost

 

Отговор (върнат от сървъра):

HTTP/1.0 404 Not Found

MIME-Version: 1.0

Content-type: text/html

 

<html> Requested document not found! </html>

 

Пример 4:

Неподдържана заявка (изпратена от клиента):

POST http://localhost/nakov/index.php HTTP/1.0

Accept: */*

 

Отговор (върнат от сървъра):

HTTP/1.0 501 Not Implemented

MIME-Version: 1.0

Content-type: text/html

 

<html> Not implemented </html>

 


Проект 1.3 – Simple HTTP Proxy Server:

Да се напише програма на Java, която използвайки възможностите на пакета java.net реализира прост HTTP Proxy-сървър. Този Proxy-сървър не е нужно да е напълно работоспособен и трябва да реализира само частично действието на истинските Proxy-сървъри. Вашият сървър трябва да слуша на TCP порт 3128 и да обслужва HTTP GET заявки. Всяка HTTP GET заявка е от вида:

GET <URL> HTTP/x.y

<параметри на заявката>

 

където последнят ред е празен (съгласно HTTP протокола). Например:

GET http://localhost/nakov/index.html HTTP/1.1

Accept: */*

Host: localhost

 

Proxy-сървърът, който трябва да напишете трябва да анализира зададената HTTP заявка, да извлича от нея Web-сървъра, за който тя е предназначена и да заменя версията на HTTP протокола от края на първия ред (HTTP/x.y) с HTTP/1.0. Получената нова HTTP заявка трябва да се изпраща за изпълнение към вече известния web-сървър (host). Полученият резултат трябва да се върне обратно на клиента. Web-сървърът трябва да се извлича от URL-то, ако присъства в него или от полето Host в хедъра на заявката в противен случай. Ако не е зададен порт, се подразбира порт 80. Всички HTTP GET заявки се преобразуват до HTTP/1.0 GET заявки, защото протоколът HTTP/1.0 е по-прост за използване. Схемата на действие на Proxy-сървъра е следната:

            Клиентите изпращат HTTP GET заявки за достъп до отдалечени обекти не конкретно към Web-сървъра, на който те трябва да бъдат изпълнени, а към Proxy-сървъра, а той ги препраща и изпълнява на съответния Web-сървър и връща резултата на клиентите. (С понятията Web-сървър и HTTP сървър означаваме едно и също нещо – сървър, обслужващ заявки по протокол HTTP). След връщането на резултата на клиента, сокетът с него се затваря. За простота се предполага, че клиентът изпраща само HTTP GET заявки (т.е. такива, чийто първи ред започва с GET ). POST и HEAD заявки не се поддържат, което означава, че вашият Proxy-сървър не е напълно работоспособен, но това ограничение е поставено само за улеснение на задачата. Вашият Proxy-сървър трябва да може да обслужва няколко клиента едновременно. Не е нужно да създавате графичен потребителски интерфейс. Достатъчно е да напишете конзолно приложение, което реализира описаната функционалност.

В Интернет Proxy-сървъри се използват по няколко причини: за ускоряване достъпа до често използвани ресурси чрез кеширане; за ограничаване на достъпа до някои ресурси чрез филтриране; за достъп до отдалечени ресурси от мережа, която е зад firewall. Вашият Proxy-сървър трябва да  спира достъпа до адреси в домейна “.bg”. При заявка за достъп до такъв адрес, да се връща грешка 403 – Forbidden. Вашият малък Proxy-сървър трябва да може да се използва от страндартен Web-браузър (например Internet Explorer). Той трябва да отпечатва на стандартния изход всички клиентски заявки и съответните им отговори. При заявка към сървър, който е недостъпен по някаква причина, трябва да се върне грешка 404 – Not Found, (въпреки, че това противоречи на стандарта, според който трябва да се върне грешка с друг код). Връщането на грешка става чрез отговор на заявка по HTTP протокола подобна на следната:

HTTP/1.0 404 Not Found

MIME-Version: 1.0

Content-type: text/html

 

<html>

    Requested document not found!

</html>

където кодът на HТTP отговора е код на грешка (в случая 404).

Пример: Web-браузърът (клиентското приложение, в нашия случай Internet Explorer 6.0) се свързва на порт 3128 към вашия Simple Proxy Server и задава няколко-редова HTTP заявка. Например:

GET /index.html HTTP/1.1

Accept: */*

Accept-Language: bg

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

Host: localhost

Connection: Keep-Alive

Cache-Control: no-cache

 

Вашият Proxy-сървър прочита клиентската заявка, променя версията на HTTP протокола (намира се на първия ред), извлича името на host-а, за който е предназначена тя, свързва се към този host (в нашия пример localhost) на порт 80 и подава преработената HTTP заявка на съответния Web-сървър. Забележете, че URL-то не съдържа host-а и той трябва да се вземе от реда “Host: localhost”. Ето и преработената заявка:

GET /index.html HTTP/1.0

Accept: */*

Accept-Language: bg

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

Host: localhost

Connection: Keep-Alive

Cache-Control: no-cache

 

Web-сървърът, който слуша на порт 80 на локалната машина (localhost), връща в отговор на тази заявка поискания документ /index.html и затваря комуникационния сокет:

HTTP/1.1 200 OK

MIME-Version: 1.0

Content-type: text/html

 

<html>

    <CENTER><H1>Welcome to Nakov Web server</H1></CENTER>

</html>

Този отговор, без изменения се изпраща на клиента и сокета за комуникация с него се затвяря.

Пример 2: Web-браузърът се свързва на порт 3128 към вашия Proxy Server и задава следната HTTP заявка:

GET http://www.top.bg/ HTTP/1.0

Accept: */*

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

 

Вашият Proxy-сървър прочита клиентската заявка, вижда че host-a (www.top.bg) е в домайна .bg и връща следния отказ от облужване:

HTTP/1.1 403 Forbidden

MIME-Version: 1.0

Content-type: text/html

 

<html>

    <p align=”center”>

        Access to .BG domain is restricted.

        Contact your system administrator for more details.

    </p>

</html>

Този отговор, без изменения се изпраща на клиента. В случая host-а се взима от URL-то от първия ред на заявката.

Пример 3: Web-браузърът се свързва на порт 3128 към вашия Proxy Server и задава следната HTTP заявка:

GET / HTTP/1.1

Accept: */*

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

Host: www.niama-takuv-server.com

 

Вашият Proxy-сървър прочита клиентската заявка и се опитва да се свърже към host-a “www.niama-takuv-server.com” на порт 80, но не успява, защото няма такъв сървър. Затова се на клиента се връща следната грешка:

HTTP/1.0 404 Not Found

MIME-Version: 1.0

Content-type: text/html

 

<html>

    Requested document not found!

</html>

Хост-а се взима от полето Host на GET-заявката защото в URL-то на първия й ред го няма.

Пример 4: Web-браузърът (в нашия случай Opera 5.12) се свързва на порт 3128 към вашия Simple Proxy Server и задава следната HTTP заявка:

GET http://psstzing.dyndns.org:7001/ HTTP/1.1

User-Agent: Opera/5.12 (Windows 2000; U)  [en]

Host: psstzing.dyndns.org:7001

Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */*

Accept-Language: en

Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0

Connection: Keep-Alive, TE

 

Вашият Proxy-сървър прочита клиентската заявка, променя версията на HTTP протокола, извлича името на host-а, за който е предназначена тя, свързва се към този host (в нашия случай host-а е psstzing.dyndns.org) на порт 7001 и подава преработената HTTP заявка:

GET http://psstzing.dyndns.org:7001/ HTTP/1.0

User-Agent: Opera/5.12 (Windows 2000; U)  [en]

Host: psstzing.dyndns.org:7001

Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */*

Accept-Language: en

Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0

Connection: Keep-Alive, TE

 

Забележете, че вашият Proxy-сървър трябва да вземе името на host-а от реда “GET http://psstzing.dyndns.org:7001/ HTTP/1.1”, а не от полето Host: psstzing.dyndns.org:7001”, защото URL-то на първия ред е пълно и съдържа host-а. Web-сървърът, който слуша на порт 7001 на адрес psstzing.dyndns.org връща в отговор на тази заявка поискания документ http://psstzing.dyndns.org:7001/ (документа по подразбиране) и затваря комуникационния сокет:

HTTP/1.1 200 OK

Date: Mon, 18 Mar 2002 09:27:51 GMT

Server: Apache/1.3.14 (Unix)  (Red-Hat/Linux) mod_ssl/2.7.1 OpenSSL/0.9.5a PHP/4.0.3pl1

Last-Modified: Mon, 20 Aug 2001 03:37:17 GMT

ETag: "c4fc-c2-3b8085ed"

Accept-Ranges: bytes

Content-Length: 194

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Content-Type: text/html

 

<HTML>

<HEAD>

<TITLE>Main page</TITLE>

</HEAD>

<FRAMESET COLS="20%,80%">

<FRAME SRC="framelinks.htm" SCROOLING="AUTO">

<FRAME SRC="one.htm" NAME="RIGHT">

</FRAMESET><noframes></noframes>

</HTML>

Този отговор, без изменения се изпраща на клиента и сокета за комуникация с него се затвяря. Забележете, че полето host от HTTP заявката може да съдържа IP адрес или host или host:port. Ако не е зададен порт, се подразбира 80 (стандартния порт за услугата HTTP).

 


Проект 1.4 – Simple Mail Server:

Да се напише програма на Java, която използвайки възможностите на пакета java.net реализира прост Mail-сървър. Програмата трябва да слуша на TCP портове 25 и 110 и да обслужва съответно SMTP и POP3 заявки сългасно SMTP и POP3 протоколите. Сървърът трябва да се състои от 2 части – SMTP сървър и POP3 сървър, които поддържат 3 фиксирани потребителя на системата съответно с имена user1, user2 и user3. За всеки от тях трябва да се създаде пощенска кутия (спъсък от текстови съобщения, който първоначално е празен). Тази пощенска кутия се използва за получаване и съхранение на съобщенията за този потребител. При осъществяване на връзка със SMTP сървъра, той трябва да поздравява клиентите си със съобщението: “220 Simple mail server”. След поздрава SMTP сървърът трябва да отговаря на следните команди:

HELO hostname – връща съобщение “250 Welcome hostname”.

MAIL FROM: <sender_email> – връща съобщение “250 sender_email Sender OK”.

RCPT TO: <recipient_email>

        ако recipient_email e един от вградените потребители (user1, user2 или user3) връща съобщение “250 recipient_email Recipient OK“.

         ако recipient_email не e един от вградените потребители, връща “550 recipient_email Recipient not found on this server “.

DATA

        ако командата RCPT TO е завършила с успех (с код 250), връща съобщение “354 Enter mail, end with "." on a line by itself” след което прочита информацията, която клиента изпраща до срещане на първата точка сама на ред. След това връща съобщение “250 Message delivered” и добавя в пощенската кутия на потребителя-получател (взима името му от команадата RCPT TO) новото съобщение. Предполага се, че текстът на съобщението не може да съдържа редове, които започват със символа точка.

        ако командата RCPT TO е завършила с неуспех (с код, различен от 250), връща съобщение “503 Invalid state”.

QUIT – връща съобщение “221 Bye” и затваря сокета.

При непозната команда SMTP сървърът трябва да отговаря с: “500 Invalid command”. За командите MAIL FROM и RCPT TO не е задължително e-mail адресите да са заградени от символите “<” и “>”. Трябва да се позволяват и двата варианта (със и без “<”,”>”).

При осъществяване на връзка със POP3 сървъра, той трябва да поздравява клиентите си със съобщението: “+OK POP3 server ready”. След това POP3 сървърът трябва да отговаря на следните команди:

USER username – връща съобщение “+User OK, please send your password”.

PASS password

        ако username съвпада с password и съвпада с ”user1” или с “user2” или с “user3” връща съобщение “+OK”.

        в противен случай връща съобщение “-ERR Invalid username/password”.

LIST – връща информация за пощенската кутия на потребителя username в следния формат:

+OK X messages

1 YYY

2 YYY

      ...

X YYY

.

където X е броят съобщения в пощенската кутия на потребителя username, а на следващите X реда стоят числата от 1 до X следвани от размера в байтове YYY на всяко от съобщенията от 1 до X и на следващия ред има една точка (сигнализираща края на списъка).

RETR X

– ако X е валиден номер на съобщение, връща следния отговор:

+OK message X

<message text>

.

– ако X не е валиден номер на съобщение, връща отговор “-ERR No such message”.

QUIT – връща съобщение “+ОК Bye” и затваря сокета.

При невалидна команда трябва да се извежда съобщение “-ERR Invalid command”. За да бъдат изпълнявани командите LIST и RETR, е необходимо клиентът първо успешно да е преминал командите user и pass, т.е. да е получил отговор започващ с “+” и на двете. В противен случай командите LIST и RETR връщат съобщение за грешка “-ERR Invalid state”.

Вашият Mail-сървър трябва да бъде програма, която може да обслужва няколко клиента едновременно както по SMTP, така и по POP3 протокола, като се грижи за синхронизация на достъпа до пощенските кутии (става въпрос за синхронизация на достъпа до пощенската кутия като структура от данни в паметта, а не за синхронизация на ниво сесия). Пощенските кутии трябва да стоят само в паметта на сървъра, без да се съхраняват на друго място (и разбира се, да губят съдържанието си при спиране на сървъра). Не е нужно да създавате графичен потребителски интерфейс. Достатъчно е да напишете конзолно приложение, което реализира описаната функционалност.

Пример: Отваряме връзка с Mail-сървъра на порт 25 (SMTP) и водим диалог със сървъра. Командите на клиента са дадени с префикс “Client:”,  а на сървъра с префикс “Server:”. В този пример потребителят се опитва да изпрати поща до непознат за сървъра адрес, а след това изпраща писмо до user1, писмо до user3 и още едно писмо до user1:

Server: 220 Simple mail server

Client: HELO www.nakov.com

Server: 250 Welcome www.nakov.com

Client: MAIL FROM: <mincho_penchov@yahoo.com>

Server: 250 mincho_penchov@yahoo.com Sender OK

Client: RCPT TO: <gincho_praschev@abv.bg>

Server: 550 gincho_praschev@abv.bg Recipient not found on this server

Client: Skapan server!

Server: 500 Invalid command

Client: RCPT TO: user1

Server: 250 user1 Recipient OK

Client: DATA

Server: 354 Enter mail, end with "." on a line by itself

Client: Hi, user1!

Client: .

Server: 250 Message delivered

Client: DATA

Server: 503 Invalid state

Client: MAIL FROM: baba_yaga@the-hell.com

Server: 250 baba_yaga@the-hell.com Sender OK

Client: RCPT TO: user3

Server: 250 user3 Recipient OK

Client: DATA

Server: 354 Enter mail, end with "." on a line by itself

Client: Hi, user3!

Client: .

Server: 250 Message delivered

Client: MAIL FROM: baba_yaga@the-hell.com

Server: 250 baba_yaga@the-hell.com Sender OK

Client: RCPT TO: user1

Server: 250 user1Recipient OK

Client: DATA

Server: 354 Enter mail, end with "." on a line by itself

Client: Hi, user1,

Client: Greetings from Baba Yaga!

Client: .

Server: 250 Message delivered

Client: QUIT

Server: 221 Bye

 

След това отваряме връзка към Mail-сървъра, но този път на порт 110 (където се обслужва услугата POP3) и водим диалог със сървъра.  Опитваме се да взезем с невалидна парола, влизаме успешно като потребител user1 и му прочитаме съобщенията. Отново командите на клиента са дадени с префикс “Client:”,  а на сървъра с префикс “Server:”. Ето и диалога:

Server: +OK POP3 server ready

Client: USER pencho_ginchev

Server: +User OK, please send your password

Client: LIST

Server: -ERR Invalid state

Client: PASS tajna

Server: -ERR Invalid username/password

Client: USER user1

Server: +User OK, please send your password

Client: PASS user1

Server: +OK

Client: LIST

Server: +OK 2 messages

Server: 1 11

Server: 2 37

Server: .

Client: Samo tolkowa li bre? Iskam oshte e-mail!

Server: -ERR Invalid command

Client: RETR 1

Server: +OK message 1

Server: Hi, user1!

Server: .

Client: RETR 37

Server: -ERR No such message

Client: RETR 2

Server: +OK message 1

Server: Hi, user1,

Server: Greetings from Baba Yaga!

Server: .

Client: QUIT

Server: +OK Bye

 

 


Проект 1.5 – Simple File Client/Server:

Да се напише програма на Java, която използвайки възможностите на пакета java.net реализира прост файлов сървър. Да се напише програма-клиент за този сървър.

Сървърът трябва да дава възможност на потребителя да вижда файловете в текущата директория, да сменя текущата директория, да изтегля файлове и да изпраща файлове. Началната директория (Root directory) от която се стартира потребителската сесия трябва да е фиксирана и сървърът трябва да дава достъп само до нея и нейните поддиректории. Файловият сървър трябва да слуша на TCP порт 2001 и да изпълнява следните команди, изпратени от клиента:

DIR, LIST, LS – извеждат всички файлове в текущата директория, по един на ред, като за всеки файл се дава името му и дължината му, а за всяка директория се дава името й и <DIR> вместо дължина. Да се извежда още и информация за името на текущата директория, за броя на файловете и поддиректориите в нея и за общата дължина на показаните файлове. Форматът на изхода от командите DIR, LIST, LS (които са напълно еквивалентни) трябва да е оформен по следния образец:

+Listing directory /home/nakov

 

..            <DIR>

documents     <DIR>

inetjava      <DIR>

file1.txt     117

file3.zip     3225187

file2.doc     73812

 

Total 3 files (3299116 bytes), 2 subdirectories.

.

Ако няма файлове и директории, списъкът трябва да е празен, а на последния ред да пише “Total 0 files (0 bytes), 0 subdirectories”. Директорията е относителен път спрямо началната директория (Root directory). За улеснение може да се счита, че в имената на файловете и директориите няма интервали и специални символи (като , , :, /, \ и подобни). Специалната директория “..“ означава по-горната директория и се появява само ако има такава. Забележете, че изходът от командите DIR, LIST, LS завършва с точка сама на ред. Това ще ви е от помощ при реализацията на клиента.

CD directory – сменя текущата директория, като влиза в посочената. При успех връща съобщение “+Directory changed to current_directory”, а при невъзможност да се влезе в посочената директория, връща съобщение “-Invalid directory”.

GET filename – ако файлът с име filename от текущата директория не може да бъде отворен за четене (например ако не съществува), командата връща съобщение “-Invalid file”. Ако файлът се отвори успешно, се връща размера и съдържанието на файла по следния образец:

       +File size and file contents follow:

       filesize

       <file contents (filesize bytes)>

Съдържанието на файла не е задължително да е текстово.

SEND filename

filesize

<file contents (filesize bytes)>

– изпраща файл с посоченото име filename, с посочената дължина filesize и с посоченото съдържание <file contents> на сървъра. Файлът се записва в текущата директория на сървъра. Изпратеното съдържание на файла трябва да е точно filezise байта. След получаване на файла, сървърът връща съобщение “+File filename stored”. Ако на сървъра има файл с това име или не е позволено писане в текущата директория (заради забрана от операционната система например) или поради друга причина файлът не може да се запише, сървърът трябва да върне съобщение за грешка “-Can not store file in current directory”.

            HELP – връща кратка помощна информация завършваща със символа “.” сам на ред. Тази точка е индикатор за край на помощната информация. Примерен резултат от командата:

+Valid commands are:

DIR – Lists current directory

CD directory – Changes current directory

GET filename – Retrieves given file from current directory

SEND filename

filesize

<file contents> – Sends given file to the server

HELP – Displays this help

QUIT – Closes this session

.

            QUIT – връща съобщение “+Bye” и затваря връзката с клиента (затваря сокета).

Сървърът предполага, че клиентът е коректен и не изпраща неправилни команди (или параметри на команди). Сървърът трябва да позволява няколко клиента да се обслужват едновременно.

Клиентското приложение, което трябва да напишете трябва да се свързва с файловия сървър и да препраща командите, които вие пишете, към него, а върнатия резултат от тези команди да отпечатва на конзолата. За улеснение на потребителя при получаване на файлове е необходимо при успешен отговор на сървъра на командата GET filename, върнатият файл да се запише в работната директория на клиента. За улеснение на изпращането на файлове, клиентът трябва да разбира командата

UPLOAD filename

която трябва автоматично да преобразува в команда към сървъра SEND с подходящи параметри. Ако файлът filename не съществува в работната директория на клиента, командата UPLOAD трябва да се игнорира, а на потребителя да бъде изведено съобщение “Can not find file filename”. Работната директория на клиента може да фиксирана (например C:\TEMP) или да се използа текущата (тази от която се стартира Java виртуалната машина).

            Както за сървъра, така и за клиента, не е нужен графичен интерфейс. Достатъчно е да се напише конзолно приложение, което покрива описаната функционалност.

            Пример: Клиентското приложение се свързва със файловия сървър и потребителят разглежда файловете по сървъра, след това издърпва няколко файла и накрая изпраща един файл на сървъра. Междувременно той не знае командите и ги разучава по метода с опити и грешки:

Client: ALO

Server: -Invalid command

Client: USER pencho

Server: -Invalid command

Client: HELP

Server: +Valid commands are:

Server: DIR – Lists current directory

Server: CD directory – Changes current directory

Server: GET filename – Retrieves given file from current directory

Server: SEND filename

Server: filesize

Server: <file contents> – Sends given file to the server

Server: HELP – Displays this help

Server: QUIT – Closes this session

Server: .

Client: OK, now I know the commands. Lets have some fun...

Server: -Invalid command

Client: DIR

Server: +Listing directory /

Server:

Server: docs         <DIR>

Server: books        <DIR>

Server: InetJava     <DIR>

Server: PrAnKa       <DIR>

Server:

Server: Total 0 files (0 bytes), 4 subdirectories.

Server: .

Client: CD docs

Server: +Directory changed to /docs

Client: DIR

Server: +Listing directory /docs

Server:

Server: ..                  <DIR>

Server: passwords.txt      55

Server: HTTP_protokol.zip  211458

Server:

Server: Total 2 files (211503 bytes), 0 subdirectories.

Server: .

Client: GET passwords.txt

Server: +File size and file contents follow:

Server: 55

Server: user: niki

Server: password: niki

Server:

Server: user: test

Server: password: test123

Client: GET SMTP-POP3-protokols.zip

Server: -Can not find file SMTP-POP3-protokols.zip

Client: CD books

Server: -Invalid directory

Client: CD /books

Server: -Invalid directory

Client: CD /

Server: -Invalid directory

Client: CD ..

Server: +Directory changed to /

Client: CD ..

Server: -Invalid directory

Client: CD books

Server: +Directory changed to /books

Client: DIR

Server: +Listing directory /books

Server:

Server: ..                         <DIR>

Server: more_books                <DIR>

Server: Thinking_in_Java.zip      2812397

Server: SQL_in_21_days.zip        332865

Server: readme.txt                131

Server:

Server: Total 3 files (3145393 bytes), 1 subdirectories.

Server: .

Client: GET readme.txt

Server: +File size and file contents follow:

Server: 131

Server: Thinking_in_Java.zip – Thinking in Java (in PDF), Bruce Eckel

Server: SQL_in_21_days.zip – Teach Yourself SQL in 21 Days, Second Edition

Client: SEND test.txt

Client: 5

Client: test  (символите са 5, защото има символ \n за край на ред след думата test”)

Server: +File test.txt stored

Client: LIST

Server: +Listing directory /books

Server:

Server: ..                         <DIR>

Server: more_books                <DIR>

Server: test.txt                  5

Server: Thinking_in_Java.zip      2812397

Server: SQL_in_21_days.zip        332865

Server: readme.txt                131

Server:

Server: Total 4 files (3145398 bytes), 1 subdirectories.

Server: .

Client: QUIT

Server: +Bye

 

Последна версия на този документ можете да намерите от сайта на курса:

http://inetjava.sourceforge.net.

Коментари по задачите можете да публикувате във форума на курса:

http://sourceforge.net/forum/forum.php?forum_id=152811

Автор на проектите: Светлин Наков

Последна промяна: 27.03.2002