【学习笔记】python实现的套接字socket

#############2014.5.13 update##############

#更新了多进程服务端的bug:客户端强行关闭会出错#

#########################################


之前说要学学python,认真看看《python核心编程》这本书,因为当时手头上的工作还没结束,也就没有怎么去看,这两天刚好赶上五一,便有了几天时间来看一下。


在了解了基本语法之后,我还是比较偏向于从网络编程作为切入点来进一步学习一门语言。所以今天就写一写简单的socket套结字的实现。


先来客户端的代码,因为之后服务端会有一些改进(SocketServer模块),而客户端基本就这样了:)

作用:从键盘接收字符串并发给服务端,然后接收服务器发来的带时间戳的回执。

客户端代码

#!/usr/bin/env python
#coding=utf-8
# 
# Author:		xusongqi@live.com
# 
# Created Time: 2014年04月30日 星期三 13时19分56秒
# 
# FileName:     tcp_sock_client.py
# 
# Description: 单线程tcp套结字客户端 

from socket import *

HOST = 'localhost'	#主机名
PORT = 21567		#端口号,显然要和客户端的端口号保持一致
BUFSIZ = 1024		#缓冲区大小设为1K
ADDR = (HOST, PORT)	#地址为主机名和端口号组成的元组

tcp_sock_client = socket(AF_INET, SOCK_STREAM)	#SOCK_STREAM即选择连接为tcp
tcp_sock_client.connect(ADDR)	#使用connect函数进行连接

#循环发送与接收,从这句话看这个套结字是个长连接
while True:		
	data = raw_input('>')
	if not data:	#如果没有写入数据,跳出循环并断开连接
		break
	tcp_sock_client.send(data)	#将数据发送到服务端
	data = tcp_sock_client.recv(BUFSIZ)	#接收从服务器发来的带时间戳的返回信息
	if not data:	#如果从服务器收到的信息为空:跳出循环并断开连接
		break
	print data		#打印服务器发来的信息

tcp_sock_client.close()	#断开连接


阻塞式单线程的服务端

然后是服务端的,嗯,这是最简单的一个服务端,前几天写的。

#!/usr/bin/env python
#coding=utf-8
# 
# Author:		xusongqi@live.com
# 
# Created Time: 2014年04月21日 星期一 11时59分44秒
# 
# FileName:     tcp_sock_server.py
# 
# Description:  单线程tcp套结字服务端

from socket import *
from time import ctime

HOST = ''				#主机名为空,表示bind()可以绑定在所有的有效地址上
PORT = 21567			#端口号要和客户端一样
BUFSIZ = 1024			#缓冲区,此处设为和客户端一样大小
ADDR = (HOST, PORT)		#地址元组

tcp_sock_server = socket(AF_INET, SOCK_STREAM)	#SOCK_STREAM:使用tcp协议
tcp_sock_server.bind(ADDR)		#bind()绑定地址元组,当前为绑定端口21567,允许所有访问该端口的主机访问服务端
tcp_sock_server.listen(5)		#listen方法的参数指定了最大连接数

while True:		#开启服务器
	print 'waiting for connection...'	#启动反馈
	tcp_sock_client, addr = tcp_sock_server.accept()	#新的描述符接收来访的客户
	print '...connection from:',addr	#接收反馈

	while True:		#死循环代表了长连接
		data = tcp_sock_client.recv(BUFSIZ)	#接收客户端信息
		if not data:	#为空则断开
			break
		tcp_sock_client.send('[%s]%s' % (ctime(), data))	#返回带时间戳的回执

	tcp_sock_client.close()	#关闭客户端描述符
tcp_sock_server.close()	#关闭服务端描述符


好了,现在我们有了比较简单的一对套接字,但是看起来弱爆了,因为它同时只支持一个用户的访问,并且还是阻塞式的.....

那么我们现在给它加点料~改成支持多用户同时访问的如何?这个看起来不错。如果要支持多个用户的同时访问,就需要使用系统函数fork(),它被包含在os包里。

先上一个简单的调用fork的例子:

#!/usr/bin/env python

import os
from time import sleep

pid=os.fork()

if not pid:
        sleep(2)
        print "world"
else:
        print "hello"
        sleep(3)

这个程序会fork一个子进程(pid返回0),然后父进程会打印hello并睡3秒,与此同时子进程会睡2秒然后打印world,于是屏幕上出现:"hello world"。

好了有了fork函数我们就能写出支持多用户的具有多进程的服务端了,now,begin~

#!/usr/bin/env python
#coding=utf-8
# 
# Author:		xusongqi@live.com
# 
# Created Time: 2014年04月30日 星期三 14时42分03秒
# 
# FileName:     tcp_sock_server_multi_thread.py
# 
# Description:  

from socket import *
from time import ctime
import os
import sys

HOST = ''				#主机名为空,表示bind()可以绑定在所有的有效地址上
PORT = 21567			#端口号要和客户端一样
BUFSIZ = 1024			#缓冲区,此处设为和客户端一样大小
ADDR = (HOST, PORT)		#地址元组

tcp_sock_server = socket(AF_INET, SOCK_STREAM)	#SOCK_STREAM:使用tcp协议
tcp_sock_server.bind(ADDR)		#bind()绑定地址元组,当前为绑定端口21567,允许所有访问该端口的主机访问服务端
tcp_sock_server.listen(5)		#listen方法的参数指定了最大连接数

"""开启服务器"""
while True:		
	print 'waiting for connection...'	#启动反馈
	tcp_sock_client, addr = tcp_sock_server.accept()	#新的描述符接收来访的客户
	print '...connection from:',addr	#接收反馈
	
	"""fork子进程"""
	pid = os.fork()
	if not pid:		#pid=0:子进程	
		while True:		#死循环代表了长连接
			tcp_sock_server.close()	#关闭服务端描述符
			data = tcp_sock_client.recv(BUFSIZ)	#接收客户端信息
			if not data:	#为空则断开
				break
			tcp_sock_client.send('[%s]%s' % (ctime(), data))	#返回带时间戳的回执
		tcp_sock_client.close()	#关闭客户端描述符
		sys.exit(0)
	else
		tcp_sock_client.close()	#关闭客户端描述符


参考资料:

《python核心编程》


你可能感兴趣的:(学习笔记,网络编程,python)