Дәріс Python-дағы желілік қосымшалар
Сокеталармен жұмыс
IP-желілерде қолданылатын клиент-сервер архитектурасы IP-пакеттерді клиенттер мен сервер арасындағы байланыс үшін пайдаланылады. Клиент серверге сұрау жібереді, ол жауап береді. TCP/IP жағдайында клиент және сервер арасында байланыс орнатылады (әдетте екі жақты мәліметтерді жіберумен), ал UDP/IP жағдайында – клиент және сервер кепілді емес пакеттермен (дейтаграммалармен) алмасады.
Әрбір IP-желілеріндегі желілік интерфейс осы желіде бірегей адресі ( IP-адрес) бар. Ықшамдап айтқанда Интернет желісіндегі әр компьютерде өзінің IP-адресі болады. Сонымен қатар бір желілік интерфейсте бірнеше желілік порттар болуы мүмкін. Клиент қосымшасына желілік байланыс орнату үшін бос портты таңдау және өшірілген желілік интерфейсте анықталған нөмерлер портын тындайтын (listen) серверлік қосымшамен байланысын орнату керек. IP-адрес жұбы және порт сокет (ұя) –желілік байланыстың бастапқы (соңғы) нүктесін сипаттайды. TCP/IP байланысын құру үшін екі сокет керек: бірі жергілікті машинаға, ал басқасы – өшірілгенге. Осылайша, әрбір желілік байланыстың IP-адресі және жергілікті машинадағы порты, сонымен қатар IP-адресі және өшірілген машинадағы порты бар.
Socket модулі Python-дағы сокеттермен жұмыс істеу мүмкіндігін қамтамасыз етеді.
OSI моделінің деңгейлері:
Физикалық
Физикалық желі арқылы жіберілетін биттер ағыны. Физикалық желілердің параметрлерін анықтайды.
Арналық (Ethernet, PPP, ATM және т.б.)
Физикалық біртұтас желі шегіндегі, физикалық деңгейде туындаған қателіктерді жеңе отыра, ағын биттері түріндегі мәліметтерді кодтайды және декодтайды.
Желілік (IP)
Ақпараттандырылған пакеттерді түйіннен түйінге маршруттайды.
Транспорттық(TCP, UDP және т.б.)
Екі байланыс нүктелері арасындағы деректердің көрінбей жіберілуін қамтамасыз етеді.
Сеанстық
Желілік қатысушылар арасында сеанстық байланыстарды басқарады. Байланысты бастайды, координаттайды және аяқтайды.о
Ұсыну(Представления)
Мәліметтердің формалардан тәуелсіздігін қамтамасыз етіп, оларды қайта құру форматы жолымен ұсыну.
Қосымшалар(HTTP, FTP, SMTP, NNTP, POP3, IMAP және т.б.)
Нақты желілік қосымшаларды қолдайды. Хаттама сервер түріне байланысты.
Әрбір сокет коммуникациялық домендерінің біріне жатады. Socket модулі UNIX және Internet домендерін қолдайды. Әр домен өз хаттамаларының және адресацияларының мүшесін білдіреді. Бұл баяндау тек Internet доменін қозғайды, ал дәлірек айтсақ TCP/IP и UDP/IP хаттамалары, сондықтан сокетті құру кезіндегі біріктіретін доменге сілтеу үшін socket.AF_INET тұрақтысы көрсетіледі.
Мысал ретінде қарапайым клиент-серверлік жұбын қарастыру керек. Сервер жолдарды қабылдайды және клиенттерге жауап береді. Желілік құрылғыны кейде хост (host) деп атайды, сондықтан бұл термин, желілік қосымша жұмыс істейтін, компьютермен байланыс кезінде қолданылады.
Сервер:
import socket, string
def do_something(x):
lst = map(None, x);
lst.reverse();
return string.join(lst, "")
HOST = "" # localhost
PORT = 33333
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind((HOST, PORT))
while 1:
print " Порт, тыңдап тұрмын 33333"
srv.listen(1)
sock, addr = srv.accept()
while 1:
pal = sock.recv(1024)
if not pal:
break
print "алынды %s:%s:" % addr, pal
lap = do_something(pal)
print "жіберілді %s:%s:" % addr, lap
sock.send(lap)
sock.close()
Клиент:
import socket
HOST = "" # қашықтықтағы компьютер (localhost)
PORT = 33333 # қашықтықтағы компьютердегі порт
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.send("ПАЛИНДРОМ")
result = sock.recv(1024)
sock.close()
print "Алынды:", result
Ескерту:
Мысалда орыс әріптері жазылған: кодтауды көрсету қажет.
Ең алдымен, серверді жіберу қажет. Сервер локальді машинаға 33333портына және 127.0.0.1 адресіне сокет ашады. Содан кейін ол портты тыңдайды (listen()). Портта мәліметтер шыққан кезде, кіріс байланысы (accept()) қолданылады. accept() әдісі, байланыс орнатылып жатқан (Ip-адрес жұбы, қашықтықтағы машинада орналасқан порт), Socket-объектісі және қашықтықтағы компьютердің адресінің жұптарын қайтарады. Осыдан кейін клиенттермен тілдесу үшін recv() және send() әдістерін қолдануға болады. recv()-те кезекті бөлікте байттар саны беріледі. Клиенттен саны аз мәліметтер келуі мүмкін.
Клиенттің бағдарлама коды жеткілікті түрде айқын. connect() әдісі қашықтықтағы хостпен байланыс орнатады (келтірілген мысалда ол сол машинада орналасқан). Мәліметтер send() әдісімен жіберіледі және ,серверде болып жатқандармен ұқсас, recv() әдісімен алынады.
Socket модулі бірнеше қосымшаларға ие. Атап айтқанда, домендік аттар жүйесімен (DNS) жұмыс істеу үшін функциялар:
>>> import socket
>>> socket.gethostbyaddr('www.onego.ru')
('www.onego.ru', [], ['195.161.136.4'])
>>> socket.gethostbyaddr('195.161.136.4')
('www.onego.ru', [], ['195.161.136.4'])
>>> socket.gethostname()
'rnd.onego.ru'
Python жаңа нұсқасында socket.getservbyname() функциясы пайда болды. Ол Интернет-сервис аттарын көпшілік мақұлдаған порт нөмірлеріне өзгертуге мүмкіндік береді:
>>> for srv in 'http', 'ftp', 'imap', 'pop3', 'smtp':
... print socket.getservbyname(srv, 'tcp'), srv
...
80 http
21 ftp
143 imap
110 pop3
25 smtp
Сонымен қатар модуль хаттамаларды, сокет түрін, біріктірілген домендерді,және т.б. көрсету үшін көп мөлшердегі тұрақтылардан тұрады. Socket модулінің басқа функцияларын құжаттама бойынша оқу қажеттілігінде мүмкін.
Smtplib модулі
Электронды почтадағы хабарлама интернетте клиенттен серверге және серверлер арасында көбіне SMTP (Simple Mail Transfer Protocol, почтаны жіберудің қарапайым хаттамасы) хаттамасы бойынша жіберіледі. SMTP және ESMTP (SMTP кеңейтілген нұсқасы) хаттамалары RFC 821 және RFC 1869-де сипатталған. SMTP-мен жұмыс істеу үшін стандарты модулдер кітапханасында smtplib модулі бар. Электронды почта серверімен SMTP-байланысын бастау үшін, SMTP класс конструкторы көмегімен SMTP-сессиясын басқару үшін басында обьект құру керек:
smtplib.SMTP([host[, port]])
host және port параметрлері, ол арқылы почта жіберілетін, адрес және SMTP-серверінің портын береді. Үнсіз келісім бойынша port=25. Егер host берілген болса, конструктор өзі байланысты орнатады, әйтпесе connect() әдісін жеке шақыруға тура келеді. SMTP классының көшірмелері барлық таратылған SMTP-хаттамаларының командалары үшін әдістері бар, бірақ почтаны жіберу үшін конструкторды және sendmail() және quit() әдістерін шақыру жеткілікті:
# -*- coding: cp1251 -*-
from smtplib import SMTP
fromaddr = "[email protected]" # Кімнен
toaddr = "[email protected]" # Кімге
message = """From: Student <%(fromaddr)s>
To: Lecturer <%(toaddr)s>
Subject: From Python course student
MIME-Version: 1.0
Content-Type: text/plain; charset=Windows-1251
Content-Transfer-Encoding: 8bit
Сәлеметсіздерме!Мен Python тілін үйренудемін.
"""
connect = SMTP('mail.onego.ru')
connect.set_debuglevel(1)
connect.sendmail(fromaddr, toaddr, message % vars())
connect.quit()
Ескере кететіні, toaddr хабарламада (To өрісінде) және жіберілуде сәйкес келмеуі мүмкін. Мәселесінде қабылдаушы және жіберуші SMTP-сессияларында SMTP-хаттамасының командаларымен жіберіледі. Жоғарыда келтірілген мысалды жібергенде экранда дұрысталған мәлімет шығады (дұрысталу деңгейі 1-ге тең етіліп берген):
send: 'ehlo rnd.onego.ru\r\n'
reply: '250-mail.onego.ru Hello as3-042.dialup.onego.ru [195.161.147.4],
pleased to meet you\r\n'
send: 'mail FROM:<[email protected]> size=270\r\n'
reply: '250 2.1.0 <[email protected]>... Sender ok\r\n'
send: 'rcpt TO:<[email protected]>\r\n'
reply: '250 2.1.5 <[email protected]>... Recipient ok\r\n'
send: 'data\r\n'
reply: '354 Enter mail, end with "." on a line by itself\r\n'
send: 'From: Student <[email protected]>\r\n . . . '
reply: '250 2.0.0 iBPFgQ7q028433 Message accepted for delivery\r\n'
send: 'quit\r\n'
reply: '221 2.0.0 mail.onego.ru closing connection\r\n'
Бұл (біршама қысқартылған) дұрысталған мәліметтен клиент командаларды SMTP-серверіне (EHLO, MAIL FROM, RCPT TO, DATA, QUIT), жіберілгенін(send) көруге болады, ал анау, қайтарылым кодын қайтара отырып командаларды орындайды және жауап береді (reply).
SMTP-сессиясының орындалу кезінде бірнеше хаттарды бірден жіберуге болады, егер quit ( ) шақырмаса.
Негізінде, SMTP командаларын бөлекте беруге болады: бұл үшін байланыс обьектісінің, SMTP-хаттамасының бір атты командаларымен сәйкес келетін, әдістері бар (helo(), ehlo(), expn(), help(), mail(), rcpt(), vrfy(), send(), noop(), data()).
docmd() әдісінің көмегімен SMTP-серверіне ерікті командасында беруге болады. Келесі мысалда, кімде-кім уақыт өте келе кейбір домендер үшін кезекті хабарлама сақталатын почталық серверден SMTP хаттамасы бойынша өз серверіне почтаны қабылдайтындар қолдана алатын, қарапайым сценарийі көрсетілген:
from smtplib import SMTP
connect = SMTP('mx.abcde.ru')
connect.set_debuglevel(1)
connect.docmd("ETRN rnd.abcde.ru")
connect.quit()
Бұл қарапайым сценарий mx.abcde.ru серверіне rnd.abcde.ru доменіндегі негізгі почталық сервермен байланысуға әрекет жасап көруін ұсынады және барлық оған жинақталған почтаны жібереді.
smtplib.SMTP классымен жұмыс кезінде түрлі ерекше жағдайлар туындауы мүмкін. Олардың кейбір тағайындалулары төменде келтірілген:
smtplib.SMTPException
Барлық модулдердің ерекше жағдайына базалық класс.
smtplib.SMTPServerDisconnected
Сервер аяқастынан байланысты үзді (немесе сервермен байланыс орнатылмаған).
smtplib.SMTPResponseException
SMTP-сервер жауабының кодына ие барлық ерекше жағдай үшін базалық класс.
smtplib.SMTPSenderRefused
Жiберушiнi қабылдамайды
smtplib.SMTPRecipientsRefused
Барлық алушылар сервермен қабылданбаған.
smtplib.SMTPDataError
Сервер берілген хабарламаға белгісіз кодпен жауап берді.
smtplib.SMTPConnectError
Байланыс орнату кезіндегі қате.
smtplib.SMTPHeloError
Сервер HELO командасына дұрыс жауап бермеді немесе оны қабылдамады.
Poplib модулі
Тағыда бір хаттама - POP3 (Post Office Protocol, почталық хаттама) – серверде почталық жәшіктен почта қабылдау үшін қызмет етеді (хаттама RFC 1725 анықталған).
Почталық сервермен жұмыс істеу үшін олармен байланыс орнату керек және, жоғарыда қаралған мысал тәрізді, SMTP-командасының көмегімен талап етілген хабарламаларды алу. POP3 байланыс обьектісімен poplib модуліндегі POP3 конструктор классы арқылы орнатуға болады:
poplib.POP3(host[, port])
Мұндағы host - POP3-серверінің адресі, port - сервердегі порт (үнсіз келісім бойынша 110), pop_obj- POP3-серверімен жұмыс сеансын басқару үшін обьекті.
Келесі мысал POP3-байланысымен жұмыс істеу үшін негізгі әдістерді көрсетеді.
import poplib, email
# Қолданушының есептiк деректерi:
SERVER = "pop.server.com"
USERNAME = "user"
USERPASSWORD = "secretword"
p = poplib.POP3(SERVER)
print p.getwelcome()
# бiрдейлендiрудiң кезеңi
print p.user(USERNAME)
print p.pass_(USERPASSWORD)
# транзакциялау кезеңі
response, lst, octets = p.list()
print response
for msgnum, msgsize in [i.split() for i in lst]:
print "Сообщение %(msgnum)s имеет длину %(msgsize)s" % vars()
print "UIDL =", p.uidl(int(msgnum)).split()[2]
if int(msgsize) > 32000:
(resp, lines, octets) = p.top(msgnum, 0)
else:
(resp, lines, octets) = p.retr(msgnum)
msgtxt = "\n".join(lines)+"\n\n"
msg = email.message_from_string(msgtxt)
print "* От: %(from)s\n* Кому: %(to)s\n* Тема: %(subject)s\n" % msg
# msg содержит заголовки сообщения или все сообщение (если оно небольшое)
# этап обновления
print p.quit()
Ескерту:
Әлбетте, мысал нақты істеу үшін нақты есептік деректерді енгізу керек.
Сценарий орындалу кезде экранға келесідей шығарады:
+OK POP3 pop.server.com server ready
+OK User name accepted, password please
+OK Mailbox open, 68 messages
+OK Mailbox scan listing follows
Сообщение 1 имеет длину 4202
UIDL = 4152a47e00000004
* От: [email protected]
* Кому: [email protected]
* Тема: KL Online Activation
...
+OK Sayonara
Осы және басқа POP3 классының көшірмелерінің әдістері төменде сипатталған:
Әдіс | POP3 командасы | сипатталуы |
getwelcome() | POP3-сервері бойынша s жолын алады. | |
user(name) | USER name | name қолданушы атымен көрсетілген USER командасын жібереді. |
pass_(pwd) | PASS pwd | PASS командасында қолданушы кілттік сөзін жібереді. Осы командадан кейін және QUIT командасының орындалуына дейін почталық жәшік бұғатталады. |
apop(user, secret) | APOP user secret | APOP бойынша серверде идентификациялау. |
rpop(user) | RPOP user | RPOP әдісі бойынша идентификациялау |
stat() | STAT | Пошта жәшiгi туралы ақпаратпен кортежді қайтарады. Мұндағы m – хабарлама саны, l – байт бойынша почта жәшігінің өлшемі. |
list([num]) | LIST [num] | (resp, ['num octets', ...]) форматтағы хабарлама тізімін қайтарады, егер num, и "+OK num octets" көрсетілмесе, егер көрсетілсе. |
retr(num) | RETR num | Серверден num нөмерімен берілген хабарламаны жүктейді және (resp, lst, octets) серверінің жауабымен берілген кортежді қайтарады |
dele(num) | DELE num | Num нөмерімен берілген хабарламаны өшіреді |
rset() | RSET | Хабарламаны өшіру белгілерін болдырмайды. |
noop() | NOOP | Ештене істемейді (байланысуды қолдайды) |
quit() | QUIT | Серверден өшірілу. Сервер барлық қажетті өзгертулерді орындайды (хабарламаны өшіреді) және почталық жәшіктің құлыптамасын шешеді. |
top(num, lines) | TOP num lines | Команда RETR-ге ұқсас, бірақ тек тақырыпшаны және хабарлама денесінің lines жолын жүктейді. Кортежді (resp, lst, octets) қайтарады. |
uidl([num]) | UIDL [num] | "unique-id listing"-тан қысқартылған (хабралама индификаторларының бірегей тізімі). Нәтиже форматы: (resp, lst, octets), егер num көрсетілмесе, және "+OK num uniqid", егер көрсетілсе. Lst тізімі "+OK num uniqid" түріндегі жолдардан тұрады. |
Бұл кестеде num хабарлама нөмерін білдіреді (ол барлық сессия аралығында өзгертілмейді), resp – сервер жауабы, кез келген команда үшін қайтарылады, нәтижелі операциялар үшін “+OK”-тан басталады (сәтсіздік кезінде poplib.proto_error ерекше жағдайы туындайды). Octets параметрі қабылданған мәліметтердің байттар санын білдіреді. uniqid – сервермен жинақталған хабарлама идентификаторы.
POP3-сервермен жұмыс үш кезеңнен тұрады: идентификация, транзакция және жаңарту. Идентификация кезеңінде, POP3-объектсін құрғаннан кейін бірден, тек USER, PASS (иногда APOP и RPOP) командалары рұқсат етілген. Идентификациядан кейін сервер қолданушы жайлы мәліметті алады және транзакция кезеңі басталады. Бұнда қалған командалар орналастырылған. Жаңарту кезеңі QUIT командасымен шақырылады, солан кейінгі POP3-сервер берілген командалармен қолданушының почталық жәшігін жаңартады, яғни хабарламаны өшіру үшін белгіленгендерді өшіреді.