python network_python network(非常好)

关于网络编程以及socket 等一些概念和函数介绍就不再重复了,这里示例性用python 编写客户端和服务器端。

一、最简单的客户端流程:

1. Create a socket

2. Connect to remote server

3. Send some data

4. Receive a reply

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

#Socket client example in python

import socket   #for socketsimport sys  #for exitimport struct

import time

#create an INET, STREAMing sockettry:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

except socket.error:

print 'Failed to create socket'

sys.exit()

print 'Socket Created'

host = 'www.google.com';

port = 80;

try:

remote_ip = socket.gethostbyname( host )

except socket.gaierror:

#could not resolve    print 'Hostname could not be resolved. Exiting'

sys.exit()

#Connect to remote servers.connect((remote_ip , port))

print 'Socket Connected to ' + host + ' on ip ' + remote_ip

#Send some data to remote servermessage = "GET / HTTP/1.1\r\n\r\n"

try :

#Set the whole string    s.sendall(message)

except socket.error:

#Send failed    print 'Send failed'

sys.exit()

print 'Message send successfully'

def recv_timeout(the_socket,timeout=2):

#make socket non blocking    the_socket.setblocking(0)

#total data partwise in an array    total_data=[];

data='';

#beginning time    begin=time.time()

while 1:

#if you got some data, then break after timeout        if total_data and time.time()-begin > timeout:

break

#if you got no data at all, wait a little longer, twice the timeout        elif time.time()-begin > timeout*2:

break

#recv something        try:

data = the_socket.recv(8192)

if data:

total_data.append(data)

#change the beginning time for measurement                begin=time.time()

else:

#sleep for sometime to indicate a gap                time.sleep(0.1)

except:

pass

#join all parts to make final string    return ''.join(total_data)

#get reply and printprint recv_timeout(s)

#Close the sockets.close()

需要注意的是也许http 响应数据比较大,要经过多次才能完整接收,设置socket 非阻塞,设定timeout,最后join 数据;因为我们并不知道具体数据到底多大,故不能这样使用 data. s.recv(4096 , socket.MSG_WAITALL); 如果最后一次来的数据不够4096,那么将一直阻塞。输出如下:

二、最简单的服务器端流程:

1. Open a socket

2. Bind to a address(and port).

3. Listen for incoming connections.

4. Accept connections

5. Read/Send

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

import socket

import sys

HOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print 'Socket created'

try:

s.bind((HOST, PORT))

except socket.error , msg:

print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]

sys.exit()

print 'Socket bind complete'

s.listen(10)

print 'Socket now listening'

#now keep talking with the clientwhile 1:

#wait to accept a connection - blocking call    conn, addr = s.accept()

print 'Connected with ' + addr[0] + ':' + str(addr[1])

data = conn.recv(1024)

reply = 'OK...' + data

if not data:

break

conn.sendall(reply)

conn.close()

s.close()

三、上述程序的缺点是每个连接上来就回应一次就不再搭理了,显然不可取,用多线程改进如下:

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

import socket

import sys

from thread import *

HOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print 'Socket created'

#Bind socket to local host and porttry:

s.bind((HOST, PORT))

except socket.error , msg:

print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]

sys.exit()

print 'Socket bind complete'

#Start listening on sockets.listen(10)

print 'Socket now listening'

#Function for handling connections. This will be used to create threadsdef clientthread(conn):

#Sending message to connected client    conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string

#infinite loop so that function do not terminate and thread do not end.    while True:

#Receiving from client        data = conn.recv(1024)

reply = 'OK...' + data

if not data:

break

conn.sendall(reply)

#came out of loop    conn.close()

#now keep talking with the clientwhile 1:

#wait to accept a connection - blocking call    conn, addr = s.accept()

print 'Connected with ' + addr[0] + ':' + str(addr[1])

#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.    start_new_thread(clientthread ,(conn,))

s.close()

即每accept 返回一个连接,就创建一个线程对其服务。

启动server,然后开两个窗口telnet 上去,如下:

四、接下来,我们再用select 来实现,函数原型如下:

read_sockets,write_sockets,error_sockets = select(read_fds , write_fds, except_fds [, timeout]);

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

#Socket server in python using select function

import socket, select

#Function to broadcast chat messages to all connected clientsdef broadcast_data(sock, message):

#Do not send the message to master socket and the client who has send us the message    for socket in CONNECTION_LIST:

if socket != server_socket and socket != sock:

try:

socket.send(message)

except:

#broken socket connection may be, chat client pressed ctrl+c for example                socket.close()

CONNECTION_LIST.remove(socket)

if __name__ == "__main__":

CONNECTION_LIST = [] #list of socket clients    RECV_BUFFER = 4096 #Advisable to keep it as an exponent of 2    PORT = 5000

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#this has no effect, why?    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_socket.bind(("0.0.0.0", PORT))

server_socket.listen(10)

#Add server socket to the list of readable connections    CONNECTION_LIST.append(server_socket)

print "Chat server started on port " + str(PORT)

while 1:

#Get the list sockets which are ready to be read through select        read_sockets, write_sockets, error_sockets = select.select(CONNECTION_LIST, [], [])

for sock in read_sockets:

#New connection            if sock == server_socket:

#handle the case in which there is a new connection recieved through server_socket                sockfd, addr = server_socket.accept()

CONNECTION_LIST.append(sockfd)

print "Client (%s, %s) connected" % addr

#Some incoming message from a client            else:

#Data recieved from client, process it                try:

#In windows, sometimes when a Tcp program closes abruptly                    #a "Connection reset by peer" exception will be thrown                    data = sock.recv(RECV_BUFFER)

#echo back the client message                    if data:

sock.send('Ok...' + data)

#client disconnected, so remove from socket list                except:

broadcast_data(sock, "Client (%s, %s) is offline" % addr)

print "Client (%s, %s) is offline" % addr

sock.close()

CONNECTION_LIST.remove(sock)

continue

server_socket.close()

五、最后使用poll 来实现,如下:

launcelot.py

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

#!/usr/bin/env python

#coding=utf-8

#Constants and routines for supporting a certain network conversation.import sys, socket

PORT = 1060

qa = (('What is your name?', 'My name is Sir Launcelot of Camelot.'),

('What is your quest?', 'To seek the Holy Grail.'),

('What is your favorite color?', 'Blue.'))

qadict = dict(qa)

def recv_until(sock, suffix):

message = ''

while not message.endswith(suffix):

data = sock.recv(4096)

if not data:

raise EOFError('socket closed before we saw %r' % suffix)

message += data

return message

def setup():

if len(sys.argv) != 2:

print >>sys.stderr, 'usage: %s interface' % sys.argv[0]

exit(2)

interface = sys.argv[1]

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

sock.bind((interface, PORT))

sock.listen(128)

print 'Ready and listening at %r port %d' % (interface, PORT)

return sock

poll_server.py

Python Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

# An event-driven approach to serving several clients with poll().import launcelot

import select

listen_sock = launcelot.setup()

sockets = {listen_sock.fileno():listen_sock}

requests = {}

responses = {}

poll = select.poll()

poll.register(listen_sock, select.POLLIN)

while True:

for fd, event in poll.poll():

sock = sockets[fd]

#Removed closed sockets from our list.        if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL):

poll.unregister(fd)

del sockets[fd]

requests.pop(sock, None)

responses.pop(sock, None)

#Accept connections from new sockets.        elif sock is listen_sock:

newsock, sockname = sock.accept()

newsock.setblocking(False)

fd = newsock.fileno()

sockets[fd] = newsock

poll.register(fd, select.POLLIN)

requests[newsock] = ''

#Collect incoming data until it forms a question.        elif event & select.POLLIN:

data = sock.recv(4096)

if not data: #end of file                sock.close()    # make POLLNVAL happen next time                continue

requests[sock] += data.replace('\r\n', '')

if '?' in requests[sock]:

question = requests.pop(sock)

answer = dict(launcelot.qa)[question]

poll.modify(sock, select.POLLOUT)

responses[sock] = answer

#Send out pieces of each reply until they are all sent        elif event & select.POLLOUT:

response = responses.pop(sock)

n = sock.send(response)

if n 

responses[sock] = response[n:]

else:

poll.modify(sock, select.POLLIN)

requests[sock] = ''

客户端需要发送launcelot.qa 其中一个问题,然后server 索引到答案发回给客户端。

参考:

《Foundations of Python Network Programming》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值