人生苦短,我用Python08:网络编程

时间:July 18, 2017 分类:

目录:

单例模式

单例模式的例是指实例(对象)

实现方式为静态方法+静态字段

在所有的实例中封装的内容相同的时候使用单例模式

模拟连接池

class ConnectionPool:
    __instance = None

    def __init__(self, port, host, name, passwd):
        self.port = port
        self.host = host
        self.name = name
        self.passwd = passwd

    @staticmethod
    def get_instance():
        if ConnectionPool.__instance:
            return ConnectionPool.__instance
        else:
            ConnectionPool.__instance = ConnectionPool()
            return ConnectionPool.__instance

    def get_connection(self):
        import random
        r = random.randrange(1, 11)
        return r

pool = ConnectionPool.get_instance()

for i in range(10):
    conn = pool

网络编程

socket是提供TCP/IP协议进行封装和反解传递数据的一个工具,也称为套接字,用于描述IP地址和端口,应用程序通过其发送和应答请求。

socket起源于Unix/Linux的基本哲学,一切事物皆文件

简单的HTTP服务

# -*- coding: utf-8 -*-

from wsgiref.simple_server import make_server

def RunServer(environ, start_response):
    start_response(status='200 OK', headers=[('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    return "why"

if __name__ == "__main__":
    httpd = make_server("", 8000, RunServer)
    print("Serving HTTP on port 8000......")
    httpd.serve_forever()

访问127.0.0.1:8000

png0801

# -*- coding: utf-8 -*-

from wsgiref.simple_server import make_server

def RunServer(environ, start_response):
    start_response(status='200 OK', headers=[('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    if url.endswith("index"):
        return "index"
    elif url.endswith("blog"):
        return "why"
    else:
        return "404"


if __name__ == "__main__":
    httpd = make_server("", 8000, RunServer)
    print("Serving HTTP on port 8000......")
    httpd.serve_forever()

png0802 png0803 png0804 根据不同url会有不同的返回值

httpd.serve_forever()的内部实质也为while循环

server端和client端进行连接

server

# -*- coding: utf-8 -*-

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9999, ))
sk.listen(5)        # socket允许接受的最大连接数

# 以上为接收客户端请求

# 连接客户端地址信息

while True:
    conn, address = sk.accept() # accept会堵塞进程
    print(conn, address)

client

# -*- conding: utf-8 -*-

import socket

obj = socket.socket()

obj.connect(('127.0.0.1', 9999,))
obj.close()

执行结果(先启动server端,然后执行多次client端连接操作)

(<socket._socketobject object at 0x00000000024EC798>, ('127.0.0.1', 53464))
(<socket._socketobject object at 0x00000000024EC800>, ('127.0.0.1', 53465))
(<socket._socketobject object at 0x00000000024EC798>, ('127.0.0.1', 53466))
(<socket._socketobject object at 0x00000000024EC800>, ('127.0.0.1', 53468))
(<socket._socketobject object at 0x00000000024EC798>, ('127.0.0.1', 53469))
(<socket._socketobject object at 0x00000000024EC800>, ('127.0.0.1', 53470))

server端对client端连接进行应答,client接收应答

对于python2

server端

# -*- coding: utf-8 -*-

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9999, ))
sk.listen(5)        # socket允许接受的最大连接数

# 以上为接收客户端请求

# 连接客户端地址信息

while True:
    conn, address = sk.accept() # accept会堵塞进程
    conn.sendall("Connect server success!") # 对连接进行应答
    print(conn, address)

client端

# -*- conding: utf-8 -*-

import socket

obj = socket.socket()

obj.connect(('127.0.0.1', 9999,))
a = obj.recv(1024)
print a
obj.close()

执行结果

Connect server success!

另外对于

对于python3

其实主要的差别还是在于python2对于传输数据,直接就转换成byte,而对于python3,要通过byte方法进行转化,接收的时候也需要将字节转化成字符串。只需要对这个点进行修改即可

server端

conn.sendall(bytes("Connect server success!", encoding = "utf-8"))

client端

ret_str = str(a, encoding = "utf-8")
print(ret_str)

server端对client端的输入进行处理和应答

对于python2

server端

# -*- coding: utf-8 -*-

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9999, ))
sk.listen(5)        # socket允许接受的最大连接数

# 以上为接收客户端请求

# 连接客户端地址信息

while True:
    conn, address = sk.accept() # accept会堵塞进程
    conn.sendall("Connect server success!") # 对连接进行应答
    # conn.sendall(bytes("Connect server success!", encoding = "utf-8"))
    while True:
        ret_str = conn.recv(1024)
        # ret_bytes = conn.recv(1024)
        # ret_str = str(ret_bytes, encoding = "utf-8")
        if ret_str == "q":  # 如果接收到q,退出循环
            break
        else:   # 进行返回
            conn.sendall(ret_str + " why get")
            # conn.sendall(bytes(ret_str + " why get", encoding = "utf-8"))

client

# -*- conding: utf-8 -*-

import socket

obj = socket.socket()

obj.connect(('127.0.0.1', 9999,))
ret_str = obj.recv(1024)
# ret_bytes = obj.recv(1024)
# ret_str = str(ret_bytes, encoding = "utf-8")
print ret_str

while True:
    inp = raw_input("sendmsg:")
    # inp = input("sendmsg:")
    if inp == "q":
        obj.sendall(inp)
        # obj.sendall(bytes(inp, encoding = "utf-8"))
        break
    else:
        obj.sendall(inp)
        # obj.sendall(bytes(inp, encoding = "utf-8"))
        ret_str = obj.recv(1024)
        # ret_bytes = obj.recv(1024)
        # ret_str = str(ret_bytes, encoding = "utf-8")
        print(ret_str)

obj.close()

执行结果

Connect server success!
sendmsg:1
1 why get
sendmsg:2
2 why get
sendmsg:q

对于python3

server端

# -*- coding: utf-8 -*-

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9999, ))
sk.listen(5)        # socket允许接受的最大连接数

# 以上为接收客户端请求

# 连接客户端地址信息

while True:
    conn, address = sk.accept() # accept会堵塞进程
    conn.sendall("Connect server success!") # 对连接进行应答
    # conn.sendall(bytes("Connect server success!", encoding = "utf-8"))
    while True:
        ret_str = conn.recv(1024)
        # ret_bytes = conn.recv(1024)
        # ret_str = str(ret_bytes, encoding = "utf-8")
        if ret_str == "q":  # 如果接收到q,退出循环
            break
        else:   # 进行返回
            conn.sendall(ret_str + " why get")
            # conn.sendall(bytes(ret_str + " why get", encoding = "utf-8"))

client端


模拟FTP

server端

# -*- coding=utf-8 -*-
import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 50070,))
sk.listen(5)
while True:
    conn, address = sk.accept()
    conn.sendall("welcome use why ftp")
    # 需要传输文件大小
    file_size = conn.recv(1024)
    print(file_size)
    total_size = int(file_size)
    # 需要传递
    has_recv = 0
    f = open("text.txt","wb")
    while True:
        if total_size == has_recv:
            break
        data = conn.recv(1024)
        f.write(data)
        has_recv += len(data)

    f.close()

client端

# -*- coding=utf-8 -*-
import socket
import os

obj = socket.socket()
obj.connect(("127.0.0.1", 50070,))

ret = obj.recv(1024)
print ret

# 发送数据长度
size = os.stat("httpd.py").st_size
obj.sendall(str(size))  # 获取的长度为int类型,需要转化为str

# 发送数据
with open("httpd.py","rb") as f:
    for line in f:
        obj.sendall(line)


obj.close()

执行结果

  • 在本地生成了text.txt文件,内容与httpd.py内容一样。
  • 不过也会出现失败的情况,主要原因是粘包的问题导致的

粘包问题的产生主要是因为发送文件长度和数据同时写入文件缓冲区进行发送,导致的