zoukankan      html  css  js  c++  java
  • Python核心编程——Chapter16

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

    Let‘s go!

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

    难度不大。

    #tsTclnt.py
    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    from socket import *
    import sys
    
    if(len(sys.argv) < 3):
        HOST = 'localhost'
        PORT = 21567
    else:
        HOST = sys.argv[1]
        PORT = int(sys.argv[2])
    
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpCliSock = socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    
    while True:
        data = raw_input('> ')
        if not data:
            break
        tcpCliSock.send(data)
        data = tcpCliSock.recv(BUFSIZ)
        if not data:
            break
        print data
    
    tcpCliSock.close()
    #tsUclnt.py
    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    from socket import *
    import sys
    
    if(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 = 1024
    ADDR = (HOST,int(PORT))
    
    udpCliSock = socket(AF_INET,SOCK_DGRAM)
    
    while True:
        data = raw_input('> ')
        if not data:
            break
        udpCliSock.sendto(data,ADDR)
        data,ADDR = udpCliSock.recvfrom(BUFSIZ)
        if not data:
            break
        print data
    
    udpCliSock.close()

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

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

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

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    from socket import *
    import time,os
    
    HOST = ''
    PORT = 21567
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpSerSock = socket(AF_INET,SOCK_STREAM)
    tcpSerSock.bind(ADDR)
    tcpSerSock.listen(5)
    
    while True:
        print 'waiting for connection...'
        tcpCliSock,addr = tcpSerSock.accept()
        print '...connected from:',addr
    
        while True:
            data = tcpCliSock.recv(BUFSIZ)
            data = data.strip()
            if not data:
                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 import ThreadingMixIn,TCPServer,StreamRequestHandler
    import time,os,re
    
    class TxRequestHandler(StreamRequestHandler):
        def handle(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.name
            elif 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+"
    ")
    
    class TxServer(ThreadingMixIn,TCPServer):
        allow_reuse_address = 1
    
    serveraddr = ('',8765)
    srvr = TxServer(serveraddr,TxRequestHandler)
    srvr.serve_forever()

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

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

    服务器端:

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    from socket import *
    from time import ctime
    
    HOST = ''
    PORT = 21567
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpSerSock = socket(AF_INET,SOCK_STREAM)
    tcpSerSock.bind(ADDR)
    tcpSerSock.listen(5)
    
    while True:
        print 'waiting for connection...'
        tcpCliSock,addr = tcpSerSock.accept()
        print '...connected from:',addr
    
        while True:
            rdata = tcpCliSock.recv(BUFSIZ)
            if not rdata:
                break
            print rdata
            sdata = raw_input(">")
            tcpCliSock.send('[%s] %s' % (ctime(),sdata))
        tcpCliSock.close()
    
    tcpSerSock.close()

    客户端:

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    from socket import *
    import sys
    
    if(len(sys.argv) < 3):
        HOST = 'localhost'
        PORT = 21567
    else:
        HOST = sys.argv[1]
        PORT = int(sys.argv[2])
    
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpCliSock = socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    
    while True:
        data = raw_input('> ')
        if not data:
            break
        tcpCliSock.send(data)
        data = tcpCliSock.recv(BUFSIZ)
        if not data:
            break
        print data
    
    tcpCliSock.close()

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

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

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

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

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

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

    服务器端:

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    import socket,traceback,os
    from threading import *
    
    host = ''
    port = 51423     #监听所有的接口
    
    #接受消息的线程
    def handlerecv(clientsock):
        print "New child",currentThread().getName()
        print "Got connection from",clientsock.getpeername()
        while True:
            data = clientsock.recv(4096)
            if not len(data):
                break
            print data
        clientsock.close()
    
    #发送消息的线程
    def handlesend(clientsock):
        while True:
            data = raw_input(">")
            data = data + "
    ";   #加上换行,好看一点。
            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)
    
    while True:
        try:
            clientsock,clientaddr = s.accept()
        except KeyboardInterrupt:
            raise
        except:
            traceback.print_exc()
            continue
    
        t = 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 *
    import sys
    from threading import *
    
    if(len(sys.argv) < 3):
        HOST = 'localhost'
        PORT = 51423
    else:
        HOST = sys.argv[1]
        PORT = int(sys.argv[2])
    
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
        
    def handlesend(tcpCliSock):
        while True:
            sdata = raw_input('> ')
            if not sdata:
                break
            tcpCliSock.send(sdata)
    
        tcpCliSock.close()
    
    tcpCliSock = socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    
    #建立发送消息的线程
    s = Thread(target = handlesend,args=[tcpCliSock])
    s.setDaemon(1)
    s.start()
    
    while True:
        rdata = tcpCliSock.recv(BUFSIZ)
        if not rdata:
            break
        print rdata
    tcpCliSock.close()

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

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

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

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

    服务器端:

    #!/usr/bin/env python
    # _*_ coding: utf8 _*_
    
    from socket import *
    from time import ctime
    import threading
    from string import split
    
    HOST = ''
    PORT = 21567
    BUFSIZE = 1024
    ADDR = (HOST, PORT)
    
    def Deal(sck, username, room):
        while True:
            data = sck.recv(BUFSIZE)
            for i in  clients[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":
                del clients[room][username]    
                sck.send(data)
                sck.close()
                break
                
    
    chatSerSock = socket(AF_INET, SOCK_STREAM)
    chatSerSock.bind(ADDR)
    chatSerSock.listen(5)
    
    clients = {"":{},}
    
    while True:
        print 'waiting for connection...'
        chatCliSock, addr = chatSerSock.accept()
        print "...connected romt: ", addr
        data = chatCliSock.recv(BUFSIZE)
        username, room = split(data)
        print username
        if not clients.has_key(room):
            clients[room] = {}
        if clients[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 import ctime
    import threading
    import random
    from sys import argv, exit, stdout
    from getopt import gnu_getopt, GetoptError
    
    
    
    
    help_info = ["cs.py [ -h | --help | -u | --username] username",
        "	-h or --help	显示帮助信息",
        "	-u or --username指定用户名",
        "	-r or --room	指定房间"]
    def help():
        for i in help_info:
            print i
    
    
    
    def Send(sck, test):
        while True:
            data = raw_input('>')
            sck.send(data)
            if  data == "quit":
                break
    def Recieve(sck, test):
        while True:
            data = sck.recv(BUFSIZ)
            if data == "quit":
                sck.close()
                break
            str = "
    " + data + "
    >" 
            stdout.write(str)
    
    HOST = 'localhost'
    PORT= 21567
    BUFSIZ = 1024
    ADDR = (HOST, PORT)
    threads = []
    
    if __name__ == "__main__":
        # 解析命令行参数
        try:
            opts, args = gnu_getopt(argv[1:], "hu:r:", ["help", "username=", "room="])        
        except GetoptError, err:
            print str(err)
            help()
            exit(2)
        username = ""
        room = ""
        for o, a in opts:
            if o in ("-h", "--help"):
                help()
                exit(0)
            elif o in ("-u", "--username"):
                username = a
            elif o in ("-r", "--room"):
                room = a
            else:
                print "未知选项"
                help()
                exit(2)
        if not username or not room:
            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 in range(len(threads)):
                threads[i].start()
            threads[0].join()

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

    感觉难度不大。

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    import socket,sys
    
    website = sys.argv[1]
    port = 80
    print website
    
    print "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
    
    ")
    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 import ThreadingMixIn,TCPServer,StreamRequestHandler
    import time
    
    class TimeRequestHandler(StreamRequestHandler):
        def handle(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 + "
    ")
    
    class TimeServer(ThreadingMixIn,TCPServer):
        allow_reuse_address = 1
    
    serveraddr = ('',8765)
    srvr = TimeServer(serveraddr,TimeRequestHandler)
    srvr.serve_forever()

    转载请注明出处http://www.cnblogs.com/sysu-blackbear/

    多多指教!谢谢!

  • 相关阅读:
    C#对SQLite、Access数据库操作的封装,很好用的~
    如何使用MFC连接Access数据库
    字节、十六进制字符串相互转换(asc2hex、hex2asc)
    Oracle数据库模式关系和数据备份导出导入
    Oracle数据库sql常用
    Oracle数据库的函数,存储过程,程序包,游标,触发器
    收集一下
    JS 获取随机颜色值
    IDEA webapp文件夹不识别解决方案
    使用postman请求响应Invalid CORS request
  • 原文地址:https://www.cnblogs.com/sysu-blackbear/p/3763632.html
Copyright © 2011-2022 走看看