Socket

作者: ft207741 | 来源:发表于2018-06-15 21:26 被阅读0次
一、Socket是什么
  • Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设 计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  • 所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

二、UDP(不堵塞)
######  Server ######
from socket import *
ip_port = ("127.0.0.1", 60008)
buffer_size = 1024
socobj = socket(AF_INET, SOCK_DGRAM)
socobj.bind(ip_port)

while True:
    try:
        data, addr = socobj.recvfrom(buffer_size)

        if not data: break
        print(data, addr)
        socobj.sendto(data.upper(), addr)
    except Exception as e:
        print(e)
        break


###### Client ######
from socket import *
ip_port = ("127.0.0.1", 60008)
buffer_size = 1024

socobj = socket(AF_INET, SOCK_DGRAM)

while True:
    data = input("Lion>>:").strip().encode()
    socobj.sendto(data, ip_port)
    data, addr= socobj.recvfrom(1024)
    print(data)
二、socketserver TCP多线程服务端(不堵塞)
######  Server ######
import socketserver

ip_port = ("127.0.0.1", 60007)
buffer_size = 1024

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):   # 重写handle方法
        print(self.request)  # self.request == connect
        print("--已经连接--", self.client_address)  # self.client_address == address
        while True:
            try:
                data = self.request.recv(buffer_size)
                if not data: break
                print(data, self.client_address)
                self.request.send(data.upper())
            except Exception as e:
                print(e)
                break
        self.request.close()

if __name__ == "__main__":
    s = socketserver.ThreadingTCPServer(ip_port, MyServer)   #  开启新线程 并 运行MyServer实例handle方法
    s.serve_forever()  # 一直循环开启服务器接受客户端消息


###### Client ######
from socket import *
ip_port = ("127.0.0.1", 60007)
buffer_size = 1024
socobj = socket(AF_INET, SOCK_STREAM)
socobj.connect(ip_port)

while True:
    try:
        data = input("Lion>>:").strip().encode("utf-8")
        if not data: continue
        if data == "quit": break
        socobj.send(data)
        data = socobj.recv(buffer_size)
        print(data.decode("utf-8"))
    except Exception as e:
        print(e)
        break
socobj.close()
一、验证客户端链接合法性(socketserver多线程)
######  Server ######
# from socket import *
import socketserver, os, hmac
"""
Digest 采用数字签名标准之一的RSA数字签名算法,通过先对原文进行单向哈希 (Hash)运算,
生成该文512bit的文摘(Digest),然后再对文摘用RSA算法生成数字签名,大大提高了对经过审
核被批准的公文进行数字签名的速度,使得流程系统具有对用户身份认证和...
"""
ip_port = ("127.0.0.1", 60009)
buffer_size = 1024
secret_key = b"I am the king!"

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        print("-已经连接-", self.client_address)
        if not self.outhoriz_request():
            print("-连接不合法-")
            return
        print("-连接合法 开始通信-")
        while True:
            try:
                data = self.request.recv(buffer_size)
                if not data: break
                print("server got:", data)
                self.request.send(data.upper())
            except Exception as e:
                print(e)
                break

    def outhoriz_request(self):
        urandom = os.urandom(32)   # 返回32个包含适合加密使用的随机字节的字节对象。
        self.request.send(urandom)
        my_hash = hmac.new(secret_key, urandom)      # 创建一个新的散列对象(hashing object)并返回它。
        digest = my_hash.digest()                    # 从一个hash object返回一个hash value。
        response = self.request.recv(len(digest))    # 收同样长度的hash value
        return hmac.compare_digest(response, digest) # 判断是否为同一个哈希值

if __name__ == "__main__":
    s = socketserver.ThreadingTCPServer(ip_port, MyServer)
    s.serve_forever()


###### Client ######
from socket import *
import hmac

ip_port = ("127.0.0.1", 60009)
buffer_size = 1024
key = b"I am the king!"

def outhoriz_request(socobj):
    msg = socobj.recv(32)
    my_hash = hmac.new(key, msg)
    digest = my_hash.digest()
    socobj.send(digest)

def client_handle():
    socobj = socket(AF_INET, SOCK_STREAM)
    socobj.connect(ip_port)
    outhoriz_request(socobj)
    while True:
        try:
            data = input("Lion>>:").strip().encode("utf-8")
            if not data: continue
            if data == b"quit": break
            socobj.send(data)
            print("-已经发送-")
            backdata = socobj.recv(buffer_size)
            print("Client got back data:", backdata.decode("utf-8"))
        except Exception as e:
            print(e)
            break

if __name__ == "__main__":
    client_handle()
一、Socket流重定向
  1. 在server里以“r”的模式打开 socobj.makefile("r") # 不可以用 “wb” 模式
  2. 在client里以“w”的模式打开 socobj.makefile("w")
  3. client里写完一条data需要 sys.stdout.flush()
  4. 通过客户端socobj对象的file来读写内容。
  5. socobj.makefile("w", 0) 不可以用 “wb” 模式; arg不可以是0,完全无缓冲;arg可以是1,行缓冲;
from socket import *
import time, multiprocessing, os, sys

ip_port = ("127.0.0.1", 60001)
back_log = 5

# ------ in server ------
def server1():
    pid = os.getpid()
    socobj = socket(AF_INET, SOCK_STREAM)
    socobj.bind(ip_port)
    socobj.listen(back_log)
    conn, addr = socobj.accept()
    print(conn, "connnnnnnnn")
    file = conn.makefile("r")
    for i in range(3):
        data = file.readline().strip()
        print("server %s got: [%s]" % (pid, data))

def client1():
    pid = os.getpid()
    socobj = socket(AF_INET, SOCK_STREAM)
    socobj.connect(ip_port)
    file = socobj.makefile("w")
    sys.stdout = file
    for i in range(3):
        print("pid %s,%s" % (pid, i))
        sys.stdout.flush()
        time.sleep(1.5)

if __name__ == "__main__":
    multiprocessing.Process(target=server1).start()
    client1()
一、Socket文本模式文件流和缓冲输出流
  1. conn.recv() 也能接收 socobj.makefile("w")对象file的write

  2. 立刻flush:

    • print(file=file, flush=True) 需要加参数"flush=True",就会立刻flush
    • file.write("data") 之后一行加 file.flush() 也会立刻flush
    • 在Client连接到Server时候,connect在新的Thread里运行。
for i in range(5):      # 会在10秒之后for循环结束才打印全部消息;
    sys.stdout.write("spam" + str(i))
    # sys.stdout.flush()   # 除非每条write后面都跟一条 sys.stdout.flush() 
    time.sleep(2)
  1. 如果碰到死锁:
    • 手动刷新sys.stdout.flush();
    • print(flush=True);
    • 命令行里加 python -u 强制输出;
    • conn.makefile("r", buffering=1) # 逐行flush
    • open("filename", "w", buffering=1)
###### Server ######
from socket import *

ip_port = ("127.0.0.1", 60009)
buffer_size = 1024

socobj = socket(AF_INET, SOCK_STREAM)
socobj.bind(ip_port)  # bind it to server port number
socobj.listen(5)
conn, addr = socobj.accept()

for i in range(3):
    print(i)
    data = conn.recv(buffer_size)
    print(data)

###### Client ######
from _socket import SOCK_STREAM
from socket import *
import time
ip_port = ("127.0.0.1", 60009)
buffer_size = 1024

socobj = socket(AF_INET, SOCK_STREAM)
socobj.connect(ip_port)
file = socobj.makefile("w")
for i in range(3):
    time.sleep(0.5)
    file.write("spam"+str(i))
print("egg1", file=file)
socobj.send(b"ham1")  # send会比file.write接收到的快;

相关文章

网友评论

      本文标题:Socket

      本文链接:https://www.haomeiwen.com/subject/uvfveftx.html