python 第七天

落爺英雄遲暮 提交于 2019-12-26 00:43:52

1、socket就是将下边的TCP/IP协议进行封装,留出来的接口用户通信

1.1、Socket Families

socket.AF_UNIX unix本机进程间通信

socket.AF_INET IPV4

socket.AF_INET6 IPV6

1.2、Socket Types

socket.SOCK_STREAM   #for tcp

socket.SOCK_DGRAM   #for udp

2、Socket 参数

2.1、socket.socket(family=AF_INETtype=SOCK_STREAMproto=0fileno=None)

声明socket类型,同时生成socket链接对象

2.2、s.bind(address)

s.bind(address) 将套接字绑定到地址

2.3、s.listen(backlog)

开始监听传入连接

2.4、sk.setblocking(bool)

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

2.5、sk.accept()

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
2.6、sk.connect(address)

连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误

2.7、sk.close()

关闭套接字

2.8、sk.recv(bufsize[,flag])

接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

2.9、sk.send(string[,flag])

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

2.10、sk.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

2.11、sk.settimeout(timeout)

设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

2.12、sk.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)

 

3、基本Socket实例

socket_server.py:

import socketserver = socket.socket()server.bind(('localhost',9999))  #绑定要监听的接口server.listen() #监听print("我要开始等电话了")while True:  conn, addr = server.accept() # 接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来  print("电话来了")   while True:    data = conn.recv(1024) #等着收数据    #为了防止收到是数据是Ctrl + C,是Ctrl + C的话会出现异常,其实就是收到的数据一直是空,判断如果是空,就重新监听    if not data:      print("lost...")         break    conn.send(data.upper())
server.close()
socket_client.py:import socketclient = socket.socket()  #声明socket类型,同时生成socket链接对象client.connect(('localhost',9999))while True:  msg = input(">>:").strip() #不能Send空  if len(msg) == 0:    continue  client.send(msg.encode("utf-8"))
    """在 Python3 中,bytes 和 str 的互相转换方式是    str.encode('utf-8')  转成byte    bytes.decode('utf-8') 转成str"""  data = client.recv(1024)  print(data.decode('utf-8'))  #decode默认就解成unicodeclient.close()    4、通过socket实现简单得SSHsocket ssh server:server.bind('localhost',9999)server .listen()while True:  conn,addr = server.accept()  print("new conn",addr)  whilt True:    print("等待客户指令")    data = conn.recv(1024)    if not data:      print("客户端已断开")      break    print("执行指令:"data)    cmd_res = os.popen(data.decode()).read  #接收字符串的命令,数目相关执行结果    conn.send(cmd_res.encode('utf-8'))  #如果服务端没有任何执行结果,是不会客户端发送数据的    print('send done') socket ssh client:import socketclient = socket.socket()client.connect(('localhost',9999))while True:  cmd = input(">>:").strip()  if len(cmd) == 0:    continue  client.send(cmd.encode('utf-8'))  cmd_res_size = client.recv(1024)  print("命令结果大小:",cmd_res_size.decode())client.close()以上会出现,加入服务端对输入的命令无响应,客户端就会进入等待收命令的假死状态,而且由于接收缓存区的问题,会出现粘包的问题。解决方法粘包的方法,就是先发数据的大小,客户端收到数据大小之后,进行比较,一直不断的接受,直到收到的完整的数据5、socket优化版import socketsocket ssh server:
import socket,osserver = socket.socket()server.bind(('localhost',9999))server.listen()while True:    conn,addr = server.accept()    print("new conn:",addr)    while True:        print("等待客户指令")        data = conn.recv(1024)        if not data:            print("客户端已断开")            break        print("执行指令:",data)        cmd_res = os.popen(data.decode()).read()  #接受字符串,执行结果也是字符串        print("before send",len(cmd_res.encode()))        if len(cmd_res) == 0:            cmd_res = "cmd has no output..."        conn.send(str(len(cmd_res.encode())).encode('utf-8'))  #先发大小给客户端        aaa = conn.recv(1024)  #等待确认        print(aaa.decode())        conn.send(cmd_res.encode('utf-8')) #客户端没有收到数据,因为没有数据,服务器是不会发的        print("send done")server.close()
socket ssh client:client = socket.socket()client.connect(('localhost',9999))while True:    cmd = input(">>:").strip()    # print(cmd)    if len(cmd) == 0:        continue    client.send(cmd.encode('utf-8'))    cmd_res_size = client.recv(1024)  #收到要传数据的大小    client.send(b"len is ok")  #为了防止和下边即将收到的数据粘包,对收到的数据进行回应,此种方法只能针对小于size大小的数据包    print("命令结果大小:",cmd_res_size.decode())    received_size = 0    total_size = int(cmd_res_size.decode())    received_data = b''    while received_size < total_size:   #为了防止粘包,对收到的数据进行处理        if total_size - received_size > 1024:  #只要未收到的大于1024就赋值1024,要不然赋值剩余的收取的数据            size = 1024         else:            size = total_size - received_size            print("last receive:", size)        data = client.recv(size)        received_size += len(data)        received_data += data     else:        print("cmd res recevie done...",received_size)        print(received_data.decode())#后边就可以继续加要收取的数据了,这样子和上边的数据就不会粘包了client.close()6、socket简单的ftp服务器import socket,os,hashlibserver = socket.socket()server.bind(('localhost',9999))server.listen()while True:  conn,addr = server.accpect()  print("new conn:",addr)  while True:    print("等待指令”)    data = conn.recv(1024)    if not data:      print("客户端已经断开")      break    cmd,filename = data.decode().split()  #默认已空格进行分割    print(filename)    if os.path.isfile(filename):      f = open(filename,'rb')      m = hashlib.md5()      #stat 系统调用时用来返回相关文件的系统状态信息,后边很多属性,这次只用了st_size的属性      file_size = os.stat(filename).st_size  #文件的大小      conn.send(str(file_size).encode()) #send file size      conn.recv(1024)   #wait for ack      for line in f:  #文件都是可以按照行读取的,这种不是一次性读取,这种方式是迭代器        conn.send(line)        m.update(line)      f.close()      conn.send(m.hexdigest().encode())    print(‘send done’)server.close()    ftp client: import socket,hashlibclient = socket.socket()client.connect(('localhost',9999))while True:    cmd = input(">>:").strip()    if len(cmd) == 0:continue    # python startswith() 方法用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False    if cmd.startswith("get"):        client.send(cmd.encode())        server_response = client.recv(1024)        print("server respone:",server_response)        client.send(b"ready to recv file")        m = hashlib.md5()        file_total_size = int(server_response.decode())        received_size = 0        filename = cmd.split()[1]        print(filename)        f = open(filename + ".new","wb")        while received_size < file_total_size:            if file_total_size - received_size > 1024:                size = 1024            else:                size = file_total_size - received_size                print("last receive:",size)            data = client.recv(size)            received_size += len(data)            m.update(data)            f.write(data)        else:            print("file recv done",received_size,file_total_size)            new_file_md5 = m.hexdigest()            f.close()        server_file_md5 = client.recv(1024)        print("server file md5:",server_file_md5.decode())        print("client file md5:",new_file_md5)client.close()   7、socket 用类来写1、导入socketserver 模块2. 继承socketserver.BaseRequestHandler类3.重写handle方法,在handle方法中实现所有的socket内容     4.实例化socket server:import socketserverclass MyTCPHandler(socketserver.BaseRequestHandler):  def handle(self):    while True:      try:        self.data = self.request.recv(1024).strip()  #request方法就是接收或者发送数据        if not self.data:          print("lost.....")        else:        # str.format() 其实是将括号中的文字放到前面             print("{} write:".format(self.client_address[0]))  #这些client_address都是继承父类的属性
                    print(self.client_address)                    print(self.data)                    self.request.send(self.data.upper())            except Exception as e:                print("err",e)                breakif __name__ == "__main__":    HOST, PORT = "localhost", 9999    server = socketserver.ThreadingTCPServer((HOST, PORT),MyTCPHandler)    #执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...    server.serve_forever()
socket client:
import socket,sysHOST, PORT = 'localhost',9999#sys.argv[1:] 就是提取传入的参数1包括后面的变量# data = " ".join(sys.argv[1:])# Create a socket (SOCK_STREAM means a TCP socket)sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #这是默认参数,可以直接写成 socket.socket()sock.connect((HOST,PORT))while True:    data = input(">>:").strip()    sock.sendall(data.encode('utf-8'))    received = str(sock.recv(1024).decode())    print("Sent:  {}".format(data))    print("Received: {}".format(received))sock.close()
 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!