博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 网络通信编程之tcp套接字socket
阅读量:6122 次
发布时间:2019-06-21

本文共 8695 字,大约阅读时间需要 28 分钟。

# 什么是套接字编程,什么是网络通信编程 # 可以粗俗的理解就是用IP地址和端口的通信编程 # 什么是套接字: # socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 # socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。 # socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭) # socket和file的区别: # file模块是针对某个指定文件进行【打开】【读写】【关闭】 # socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】 # 一般来说,建立服务器连接需要六个步骤。 # 第1步是创建socket对象。调用socket构造函数。 # socket=socket.socket(familly,type) # family的值:可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(对于IPV4协议的TCP和 UDP), # type参数:SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw套接字)。 # 第2步则是将socket绑定(指派)到指定地址上,socket.bind(address) # address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。 # 如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。 # 第3步,绑定后,必须准备好套接字,以便接受连接请求。 # socket.listen(backlog) # backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。 # 第4步,服务器套接字通过socket的accept方法等待客户请求一个连接: # connection,address=socket.accept() # 调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。 # accept方法返回一个含有俩个元素的元组,形如(connection,address)。 # 第一个元素(connection)是新的socket对象,服务器通过它与客户通信,最后要关闭; # 第二个元素(address)是客户的internet地址。 # 第5步是处理阶段,服务器和客户通过send和recv方法通信(传输数据)。 # 服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。 # 服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。 # recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。 # 如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接受端。 # 以后调用recv时,多余的数据会从缓冲区删除。 # 第6步,传输结束,服务器调用socket的close方法以关闭连接。 # 一般来说,建立一个简单客户连接则需要4个步骤。 # 第1步,创建一个socket以连接服务器 import socket ,socket=socket.socket(family,type) # 第2步,使用socket的connect方法连接服务器 socket.connect((host,port)) # 第3步,客户和服务器通过send和recv方法通信。 # 第4步,结束后,客户通过调用socket的close方法来关闭连接。 来一个简单的例子:
# 基于tcp套接字网络编程的服务端代码,同目录下server.pyimport socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加phone.bind(('127.0.0.1',8081)) #绑定手机卡phone.listen(5) #开机  ?5print('starting....')while True: #链接循环    conn,addr=phone.accept() #等待电话链接    print('电话线路是',conn)    print('客户端的手机号是',addr)    while True: #通信循环        try: #应对windows系统            data=conn.recv(1024) #收消息  ?1024            if not data:break #linux系统            print('客户端发来的消息是',data)            conn.send(data.upper())        except Exception:            break    conn.close()phone.close()
# 基于tcp套接字网络编程的客户端代码,同目录下client.pyimport socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8081))while True: #通信循环    msg=input('>>: ').strip()    if not msg:continue    phone.send(msg.encode('utf-8'))    print('has send===========>')    data=phone.recv(1024)    print('has recv===========>')    print(data)phone.close()

再来一个小实验:

实现一个基于tcp的套接字实现远程执行命令的操作
#!/usr/bin/env python3#coding="utf-8"# 基于tcp的套接字实现远程执行命令的操作--服务端代码romote_cmd_server.pyfrom socket import *import subprocessback_log=5buffer_size=1024tcp_server = socket(AF_INET,SOCK_STREAM)tcp_server.bind(("127.0.0.1",8000))tcp_server.listen(back_log)print("starting....")while True:    conn,addr=tcp_server.accept()    print("conn:",conn)    print("addr:",addr)    while True:        try:            cmd=conn.recv(buffer_size)            if not cmd:break            print("已经收到客户端的命令",cmd)            res=subprocess.Popen(cmd.decode("utf8"),shell=True,                                 stderr=subprocess.PIPE,                                 stdin=subprocess.PIPE,                                 stdout=subprocess.PIPE)            err=res.stderr.read()            if err:                cmd_res=err            else:                cmd_res=res.stdout.read()            conn.send(cmd_res)        except Exception as e:            print(e)            breakconn.close()tcp_server.close()
#!/usr/bin/env python3#coding="utf-8"# 基于tcp的套接字实现远程执行命令的操作--客户端代码romote_cmd_client.pyfrom socket import *tcp_client=socket(AF_INET,SOCK_STREAM)tcp_client.connect(("127.0.0.1",8000))while True:    cmd = input(">>:").strip()    if not cmd:continue    if cmd == "quit":break    tcp_client.send(cmd.encode("utf8"))    cmd_res=tcp_client.recv(1024)    print("cmd 执行结果:",cmd_res.decode('utf8'))tcp_client.close()

 

关于基于tcp的并发多线程操作:

# 基于tcp并发多线程的服务端import socketserver# 必须继承socketserver.BaseRequestHandler为父类class FTPserver(socketserver.BaseRequestHandler):    # 必须有handle函数    def handle(self):        print("====>",self)        #====> <__main__.FTPserver object at 0x10d8d32b0>        #本类FTPserver对象        print(self.request)        #
# self.request就是conn,addr=phone.accept()的conn,即socket对象 while True: data=self.request.recv(1024) print(data) self.request.send(data.upper())if __name__ == '__main__': obj=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FTPserver) obj.serve_forever() #链接循环
# 基于tcp并发多线程的客户端,多个客户端都是一样的测试import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(("127.0.0.1",8080))while True:    x=input("客户端:").strip()    if not x:continue    phone.send(x.encode("utf8"))    data=phone.recv(1024)    print("服务端",data.decode("utf8"))phone.close()

 

基于tcp的ftp多线程上传功能:

 

# 基于tcp的ftp多线程上传服务端import socketserverimport structimport jsonimport subprocessimport osclass MYTCPServer(socketserver.BaseRequestHandler):    max_packet_size = 8192    coding='utf-8'    BASE_DIR=os.path.dirname(os.path.abspath(__file__))    server_dir='file_upload'    def handle(self):        while True:            try:                head_struct = self.request.recv(4)                if not head_struct:break                head_len = struct.unpack('i', head_struct)[0]                head_json = self.request.recv(head_len).decode(self.coding)                head_dic = json.loads(head_json)                print(head_dic)                #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}                cmd=head_dic['cmd']                if hasattr(self,cmd):                    func=getattr(self,cmd)                    func(head_dic)            except Exception:                break    def put(self,args):        file_path=os.path.normpath(os.path.join(            self.BASE_DIR,            self.server_dir,            args['filename']        ))        filesize=args['filesize']        recv_size=0        print('----->',file_path)        with open(file_path,'wb') as f:            while recv_size < filesize:                recv_data=self.request.recv(self.max_packet_size)                f.write(recv_data)                recv_size+=len(recv_data)                print('recvsize:%s filesize:%s' %(recv_size,filesize))if __name__ == '__main__':    obj=socketserver.ThreadingTCPServer(('127.0.0.1',8082),MYTCPServer)    obj.serve_forever()

 

 

# 基于tcp的ftp多线程上传客户端,好多个一样的客户端import socketimport structimport jsonimport osclass MYTCPClient:    address_family = socket.AF_INET    socket_type = socket.SOCK_STREAM    allow_reuse_address = False    max_packet_size = 8192    coding='utf-8'    request_queue_size = 5    def __init__(self, server_address, connect=True):        self.server_address=server_address        self.socket = socket.socket(self.address_family,                                    self.socket_type)        if connect:            try:                self.client_connect()            except:                self.client_close()                raise    def client_connect(self):        self.socket.connect(self.server_address)    def client_close(self):        self.socket.close()    def run(self):        while True:            inp=input(">>: ").strip()            if not inp:continue            l=inp.split()            cmd=l[0]            if hasattr(self,cmd):                func=getattr(self,cmd)                func(l)    def put(self,args):        cmd=args[0]        filename=args[1]        if not os.path.isfile(filename):            print('file:%s is not exists' %filename)            return        else:            filesize=os.path.getsize(filename)        head_dic={
'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize} print(head_dic) head_json=json.dumps(head_dic) head_json_bytes=bytes(head_json,encoding=self.coding) head_struct=struct.pack('i',len(head_json_bytes)) self.socket.send(head_struct) self.socket.send(head_json_bytes) send_size=0 with open(filename,'rb') as f: for line in f: self.socket.send(line) send_size+=len(line) print(send_size) else: print('upload successful')client=MYTCPClient(('127.0.0.1',8082))client.run()
# 操作指南:# 运行服务端# 运行各个客户端# 每个客户端里输入命令,# 例如:# put /users/alex/desktop/hello.mp4# put /users/alex/desktop/hello1.mp4# put /users/alex/desktop/hello2.mp4# ⚠注意设定服务器端上传文件夹的地址,要新建文件夹,如有绝对地址则以绝对地址为主

 

转载于:https://www.cnblogs.com/adamans/articles/6802805.html

你可能感兴趣的文章
解读自定义UICollectionViewLayout--感动了我自己
查看>>
SqlServer作业指定目标服务器
查看>>
UnrealEngine4.5 BluePrint初始化中遇到编译警告的解决办法
查看>>
User implements HttpSessionBindingListener
查看>>
抽象工厂方法
查看>>
ubuntu apt-get 安装 lnmp
查看>>
焊盘 往同一个方向增加 固定的长度方法 总结
查看>>
eclipse的maven、Scala环境搭建
查看>>
架构师之路(一)- 什么是软件架构
查看>>
jquery的冒泡和默认行为
查看>>
USACO 土地购买
查看>>
【原创】远景能源面试--一面
查看>>
B1010.一元多项式求导(25)
查看>>
10、程序员和编译器之间的关系
查看>>
前端学习之正则表达式
查看>>
配置 RAILS FOR JRUBY1.7.4
查看>>
AndroidStudio中导入SlidingMenu报错解决方案
查看>>
修改GRUB2背景图片
查看>>
Ajax异步
查看>>
好记性不如烂笔杆-android学习笔记<十六> switcher和gallery
查看>>