好吧,在拜读完《Python网络编程基础》之后,回头再搞一搞16章的网络编程吧。

Let‘s go!

16.4.修改书上示例的TCP和UDP客户端,使得服务器的名字不要在代码里写死,要允许用户指定一个主机名和端口。只有两个值都没有输入是才使用默认值。

难度不大。

#tsTclnt.py#!/usr/bin/env python#-*-coding:utf-8-*-

from socket import *

importsysif(len(sys.argv) < 3):

HOST= 'localhost'PORT= 21567

else:

HOST= sys.argv[1]

PORT= int(sys.argv[2])

BUFSIZ= 1024ADDR=(HOST,PORT)

tcpCliSock=socket(AF_INET,SOCK_STREAM)

tcpCliSock.connect(ADDR)whileTrue:

data= raw_input('>')if notdata:breaktcpCliSock.send(data)

data=tcpCliSock.recv(BUFSIZ)if notdata:break

printdata

tcpCliSock.close()

#tsUclnt.py#!/usr/bin/env python#-*- coding:utf-8 -*-

from socket import *

importsysif(len(sys.argv) < 3):

HOST= 'localhost'PORT= 21567

else:

HOST= sys.argv[1]

PORT= sys.argv[2]#print sys.argv[1],sys.argv[2]

BUFSIZ= 1024ADDR=(HOST,int(PORT))

udpCliSock=socket(AF_INET,SOCK_DGRAM)whileTrue:

data= raw_input('>')if notdata:breakudpCliSock.sendto(data,ADDR)

data,ADDR=udpCliSock.recvfrom(BUFSIZ)if notdata:break

printdata

udpCliSock.close()

16.5.修改服务器示例代码,使得它能根据不同的请求而作出应答。

这道题目本质上也不难,只需要在服务器的死循环程序加上条件判断即可。

版本1:纯TCP服务器端修改。

#!/usr/bin/env python#-*- coding:utf-8 -*-

from socket import *

importtime,os

HOST= ''PORT= 21567BUFSIZ= 1024ADDR=(HOST,PORT)

tcpSerSock=socket(AF_INET,SOCK_STREAM)

tcpSerSock.bind(ADDR)

tcpSerSock.listen(5)whileTrue:print 'waiting for connection...'tcpCliSock,addr=tcpSerSock.accept()print '...connected from:',addrwhileTrue:

data=tcpCliSock.recv(BUFSIZ)

data=data.strip()if notdata:break

if data == "date":

tcpCliSock.send('%s' %(time.ctime(time.time())))elif data == "os":

tcpCliSock.send('%s' %(os.name))elif data == "ls":

tcpCliSock.send('%s' %(os.listdir(os.curdir)))else:

tcpCliSock.send('[%s] %s' %(ctime(),data))

tcpCliSock.close()

tcpSerSock.close()

版本2:使用现成的服务器框架进行修改。

#!/usr/bin/env python#-*-coding:utf-8-*-

from SocketServer importThreadingMixIn,TCPServer,StreamRequestHandlerimporttime,os,reclassTxRequestHandler(StreamRequestHandler):defhandle(self):

req=self.rfile.readline().strip()

m= re.match('(\w+)\s+([\w+/]+)',req)if req == "date":

result=time.ctime(time.time())elif req == "os":

result=os.nameelif req == "ls":

result=str(os.listdir(os.curdir))elif m is not None and m.lastindex == 2 and m.group(1) == 'ls':

result= str(os.listdir(m.group(2)))else:

result= """date -- 服务器将返回它的当前时间

os -- 得到操作系统的信息

ls -- 得到当前目录的文件列表"""self.wfile.write(result+"\n")classTxServer(ThreadingMixIn,TCPServer):

allow_reuse_address= 1serveraddr= ('',8765)

srvr=TxServer(serveraddr,TxRequestHandler)

srvr.serve_forever()

16.7.实现一个半双工的聊天方式,其中一个人是服务端,另一个人是客户端。

其实也不难,只是将回射服务器做部分修改就可以。

服务器端:

#!/usr/bin/env python#-*- coding:utf-8 -*-

from socket import *

from time importctime

HOST= ''PORT= 21567BUFSIZ= 1024ADDR=(HOST,PORT)

tcpSerSock=socket(AF_INET,SOCK_STREAM)

tcpSerSock.bind(ADDR)

tcpSerSock.listen(5)whileTrue:print 'waiting for connection...'tcpCliSock,addr=tcpSerSock.accept()print '...connected from:',addrwhileTrue:

rdata=tcpCliSock.recv(BUFSIZ)if notrdata:break

printrdata

sdata= raw_input(">")

tcpCliSock.send('[%s] %s' %(ctime(),sdata))

tcpCliSock.close()

tcpSerSock.close()

客户端:

#!/usr/bin/env python#-*-coding:utf-8-*-

from socket import *

importsysif(len(sys.argv) < 3):

HOST= 'localhost'PORT= 21567

else:

HOST= sys.argv[1]

PORT= int(sys.argv[2])

BUFSIZ= 1024ADDR=(HOST,PORT)

tcpCliSock=socket(AF_INET,SOCK_STREAM)

tcpCliSock.connect(ADDR)whileTrue:

data= raw_input('>')if notdata:breaktcpCliSock.send(data)

data=tcpCliSock.recv(BUFSIZ)if notdata:break

printdata

tcpCliSock.close()

16.8.实现一个全双工的聊天方式,即两个人可以独立地发送和接收消息。

全双工其实原理也不太难,但是我一直傻逼了,一直用写服务器端的方法去实现客户端的程序。

我所使用的方法也是最常用的技术——多线程。以下是服务器端和客户端的编写思路:

服务器端:在服务器端我主要用了一个主线程来accept客户端的链接,没接受了一个连接,就新建两个线程,一个用于发送消息,一个用于接收消息。

客户端:思路完全不一样,由于客户端面对的只有服务器,所以主线程只能是接收消息(发送消息),然后发送消息(接收消息)作为一个线程来并发。

由于这里的数据并不是共享的,所以这里的线程写起来就很轻松,不用考虑同步问题。

服务器端:

#!/usr/bin/env python#-*- coding:utf-8 -*-

importsocket,traceback,osfrom threading import *host= ''port= 51423 #监听所有的接口

#接受消息的线程

defhandlerecv(clientsock):print "New child",currentThread().getName()print "Got connection from",clientsock.getpeername()whileTrue:

data= clientsock.recv(4096)if notlen(data):break

printdata

clientsock.close()#发送消息的线程

defhandlesend(clientsock):whileTrue:

data= raw_input(">")

data= data + "\n"; #加上换行,好看一点。

clientsock.sendall(data)#关闭连接

clientsock.close()#建立套接字

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

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

s.bind((host,port))

s.listen(1)whileTrue:try:

clientsock,clientaddr=s.accept()exceptKeyboardInterrupt:raise

except:

traceback.print_exc()continuet= Thread(target = handlerecv,args=[clientsock])

t.setDaemon(1)

t.start()

r= Thread(target = handlesend,args=[clientsock])

r.setDaemon(1)

r.start()

客户端:

#!/usr/bin/env python#-*-coding:utf-8-*-

from socket import *

importsysfrom threading import *

if(len(sys.argv) < 3):

HOST= 'localhost'PORT= 51423

else:

HOST= sys.argv[1]

PORT= int(sys.argv[2])

BUFSIZ= 1024ADDR=(HOST,PORT)defhandlesend(tcpCliSock):whileTrue:

sdata= raw_input('>')if notsdata:breaktcpCliSock.send(sdata)

tcpCliSock.close()

tcpCliSock=socket(AF_INET,SOCK_STREAM)

tcpCliSock.connect(ADDR)#建立发送消息的线程

s = Thread(target = handlesend,args=[tcpCliSock])

s.setDaemon(1)

s.start()whileTrue:

rdata=tcpCliSock.recv(BUFSIZ)if notrdata:break

printrdata

tcpCliSock.close()

16.10.实现一个多房间全双工的聊天方式,把聊天服务器改成支持多用户版本。

其实思路差不多,只不过过程有点繁琐,在服务器端要建立字典,作为房间,然后每个套接字存在字典当中,然后作适当的分发。

另外一种方法使用广播不知道可不可以了。

这里直接贴人家写的代码学习一下:

服务器端:

#!/usr/bin/env python#_*_ coding: utf8 _*_

from socket import *

from time importctimeimportthreadingfrom string importsplit

HOST= ''PORT= 21567BUFSIZE= 1024ADDR=(HOST, PORT)defDeal(sck, username, room):whileTrue:

data=sck.recv(BUFSIZE)for i inclients[room].iterkeys():if i <>username:if data <> "quit":

clients[room][i].send("[%s] %s: %s" %(ctime(), username, data))else:

clients[room][i].send("用户%s在%s退出房间%s" %(username, ctime(), room ))if data == "quit":delclients[room][username]

sck.send(data)

sck.close()breakchatSerSock=socket(AF_INET, SOCK_STREAM)

chatSerSock.bind(ADDR)

chatSerSock.listen(5)

clients= {"":{},}whileTrue:print 'waiting for connection...'chatCliSock, addr=chatSerSock.accept()print "...connected romt:", addr

data=chatCliSock.recv(BUFSIZE)

username, room=split(data)printusernameif notclients.has_key(room):

clients[room]={}ifclients[room].has_key(username):

chatCliSock.send("reuse")

chatCliSock.close()else:

chatCliSock.send("success")

clients[room][username]=chatCliSock

t= threading.Thread(target=Deal, args=(chatCliSock, username, room))

t.start()

chatSerSock.close()

客户端:

#!/usr/bin/env python#_*_ coding: utf8 _*_

from socket import *

from time importctimeimportthreadingimportrandomfrom sys importargv, exit, stdoutfrom getopt importgnu_getopt, GetoptError

help_info= ["cs.py [ -h | --help | -u | --username] username","\t-h or --help\t显示帮助信息","\t-u or --username\指定用户名","\t-r or --room\t指定房间"]defhelp():for i inhelp_info:printidefSend(sck, test):whileTrue:

data= raw_input('>')

sck.send(data)if data == "quit":break

defRecieve(sck, test):whileTrue:

data=sck.recv(BUFSIZ)if data == "quit":

sck.close()breakstr= "\n" + data + "\n>"stdout.write(str)

HOST= 'localhost'PORT= 21567BUFSIZ= 1024ADDR=(HOST, PORT)

threads=[]if __name__ == "__main__":#解析命令行参数

try:

opts, args= gnu_getopt(argv[1:], "hu:r:", ["help", "username=", "room="])exceptGetoptError, err:printstr(err)

help()

exit(2)

username= ""room= ""

for o, a inopts:if o in ("-h", "--help"):

help()

exit(0)elif o in ("-u", "--username"):

username=aelif o in ("-r", "--room"):

room=aelse:print "未知选项"help()

exit(2)if not username or notroom:

help()

exit(2)

chatCliSock=socket(AF_INET, SOCK_STREAM)

chatCliSock.connect(ADDR)

chatCliSock.send("%s %s" %(username, room))

data=chatCliSock.recv(BUFSIZ)if data == "reuse":print "用户%s已登录房间%s" %(username, room)

raw_input()

exit(1)elif data == "success":print "用户%s成功登录房间%s" %(username, room)

t= threading.Thread(target=Send, args =(chatCliSock, None))

threads.append(t)

t= threading.Thread(target=Recieve, args =(chatCliSock, None))

threads.append(t)for i inrange(len(threads)):

threads[i].start()

threads[0].join()

16.11.写一个网页客户端。自己新建一个套接字,然后发送http请求。

感觉难度不大。

#!/usr/bin/env python#-*-coding:utf-8-*-

importsocket,sys

website= sys.argv[1]

port= 80

printwebsiteprint "Creating socket...",

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)print "done."

print "Connecting to ...",

s.connect((website,port))print "done."s.send("GET /index.html HTTP/1.0\r\n\r\n")

data= s.recv(4096)print data

16-12.休眠服务器,在服务器端上面加个sleep(num)就好,在这里就不贴了。

16-13.功能太过复杂,本人渣渣,没精力写。

16-14.考虑的东西很多,水平有限,不做了。

16-15.异步和SocketServer。这个用多线程可以实现,在《python网络编程基础》上面直接有源码。使用方法都有教。

#!/usr/bin/env python#-*- coding:utf-8 -*-

from SocketServer importThreadingMixIn,TCPServer,StreamRequestHandlerimporttimeclassTimeRequestHandler(StreamRequestHandler):defhandle(self):

req=self.rfile.readline().strip()if req == "asctime":

result=time.asctime()elif req == "seconds":

result=str(int(time.time()))elif req == "rfc822":

result= time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime())else:

result= """Unhandled request.Send a line with one of the following words:

asctime -- for human-readable time

seconds -- seconds since the Unix Epoch

rfc822 -- data/time in format used for mail and news posts"""self.wfile.write(result+ "\n")classTimeServer(ThreadingMixIn,TCPServer):

allow_reuse_address= 1serveraddr= ('',8765)

srvr=TimeServer(serveraddr,TimeRequestHandler)

srvr.serve_forever()

多多指教!谢谢!

python编程16章_Python核心编程——Chapter16相关推荐

  1. python编程15章_python核心编程2 第十五章 练习

    15-1.识别下列字符串 :"bat "."bit "."but "."hat "."hit" 或 ...

  2. python课后题答案第一章_python核心编程课后习题解答第一章

    闲着没事,决定将<python核心编程>这本书的课后习题做一遍,以增加自己的编程能力. 1-1 将python安装到系统上 本人用的ubuntu系统,系统中自带了python,无需安装,本 ...

  3. python程序练习题第三章_python核心编程-第三章-习题

    1.这是python的语言特性,python先创建对象,在给变量赋值时,不需要定义变量的名称和类型,它实际是用变量引用对象.变量类型在给变量赋值时自动声明 2.原因类似变量无须声明类型 3.pytho ...

  4. python教材答案第四章_python核心编程课后习题解答第四章

    4–1. Python 对象.与所有Python 对象有关的三个属性是什么?请简单的描述一下. type.ID.value..(身份.类型.值) type()接受一个对象作为参数,并返回它的类型 id ...

  5. python第五章课后编程题答案_Python核心编程-第五章课后习题

    5-1 整形 讲讲 Python 普通整型和长整型的区别 答:在2.7版本基本淡化了区别.真要区分的话,普通整型是32位或者64位,而长整型只与PC内存有关,很大就是了 5-2 运算符 (a) 写一个 ...

  6. python核心编程怎么做_Python核心编程:8个实践性建议

    前言 我们在用Python进行机器学习建模项目的时候,每个人都会有自己的一套项目文件管理的习惯,我自己也有一套方法,是自己曾经踩过的坑踩过的雷总结出来的,现在在这里分享一下给大家,因为很多伙伴是接触P ...

  7. python语句行从解释器提示符后第几列开始_Python核心编程(第2版)PDF文档免费下载...

    第1部分 Python核心 第1章 欢迎来到Python世界 1.1 什么是Python 1.2 起源 1.3 特点 1.3.1 高级 1.3.2 面向对象 1.3.3 可升级 1.3.4 可扩展 1 ...

  8. python归一化 增大差异_简学Python第六章__class面向对象编程与异常处理

    Python第六章__class面向对象编程与异常处理 欢迎加入Linux_Python学习群 群号:478616847 目录: 面向对象的程序设计 类和对象 封装 继承与派生 多态与多态性 特性pr ...

  9. 从零学python黑马程序员_Python实战编程--从零学Python/Python应用编程丛书

    导语 内容提要 黑马程序员编著的<Python实战编程--从零学Python>涵盖了Python开发的核心知识.其中,第1-13章主要讲解的是Python的核心语法,包括基本概念和语句.风 ...

最新文章

  1. python3 字符串、十六进制字符串、数字、字节之间的转换
  2. bilibili怎么设置弹幕数量_python爬虫:bilibili弹幕爬取+词云生成
  3. python学习教程,猜数字游戏开发
  4. 利用STL离散化处理数据(unique)
  5. idea搭建可运行Servlet的Web项目[maven]
  6. 通过IDE生成和手动call调用webservice
  7. 在web项目中集成xfire的方法
  8. CVX 几何规划 两个官网样例
  9. Extjs, each中实现break、continue
  10. iOS App创建桌面快捷方式
  11. Fedora17下Firefox安装flashplayer
  12. jpa双向一对一关联外键映射
  13. 运行Arcgis和SWAT模型遇到Error Number 91和Error Number -2147467259报错怎么办?
  14. 如何规划自己的人生未来
  15. 数据泵并行parallel参数问题
  16. pl/sql Developer 1303注册码
  17. Zookeeper 客户端之 Curator
  18. 计算机硬件系统一直延用,会计电算化计算机硬件系统
  19. 个人电脑厂商艰难涉水家庭娱乐市场
  20. 说说wps jsa的ListBox控件的数组写入方法

热门文章

  1. python 库整理:Timm(1)
  2. Flink从入门到精通100篇(二十三)-基于Apache Flink的爱奇艺实时计算平台建设实践
  3. matlab实战系列之人工鱼群算法求解TSP问题原理解析(下篇源码解析)
  4. python网络爬虫爬取房价信息
  5. 【云计算】6_云数据库产品介绍
  6. Python编程基础:第五十九节 守护线程Daemon Threading
  7. JVM 生态系统 2018 调查报道
  8. 兼顾稳定和性能,58大数据平台的技术演进与实践
  9. 用最少的机器支撑万亿级访问,微博6年Redis优化历程
  10. 对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)--转