socket 编程
Posted Cloud-Tony
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket 编程相关的知识,希望对你有一定的参考价值。
C/S架构与socket 的关系:
学习socket 编程就是为完成C/S 架构的开发
socket 编程 与 互联网协议
- 学习socket的目的:目标就是掌握socket编程,开发自己的C/S架构软件
- C/S架构的软件,(软件属于应用层)是基于网络进行通信的
- 网络的核心就是一堆协议,协议就是标准,要开发一款基于网络通信的软件,就必须遵循这些标准
TCP/IP 协议族包括运输层、网络层、链路层、
socket 层:在哪???看下图
所有的互联网协议都被 socket 包涵,或者说都被socket 这一个囊括了,而socket 处于 应用层 与 运输层 之间,
那既然 socket 已经将整个互联网的协议包括在它里面了, 就不用再去研究什么 TCP/UDP这些协议了,因为socket已经为我们封装好了
,所以我们写应用程序 时 只要遵循 socket的规定,写出的程序就遵循TCP/UDP的标准了
基于文件类型的套接字家族: AF_UNIX (address and protocol familes)
基于网络类型的套接字家族:AF_INET
AF_INET6被用于ipv6,还有一些其它的地址家庭,AF_INET是使用最广泛的一个。
套接字工作流程:
打电话场景: 你有一个手机,开机,上卡,要打电话给一个朋友,先拨号,朋友听到电话铃声后拿起电话(看电话号码)并接电话,这个时候就已经建立起了连接,
,通了以后进行通话,通话结束后挂断电话,此次通话完成。
socket()模块函数用法
import socket socket.socket(socket_family,socket_type,protocal=0) #socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 #获取tcp/ip 套接字 tcpSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #获取udp/ip 套接字 udpSock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
服务端 建立连接 步骤
三种最流行的套接字类型是:stream ,datagram 和 raw套接字可以直接与TCP协议进行接口,而 raw套接字则接口到IP协议。但套接字并不限于TCP/IP #套接字模块 #使用该模块可以实现客户机与服务器套接字,要在PYTHON中建立具有TCP和流套接字的简单服务器,需要使用socket模块,利用该模块包含的和类定义,可生成通过网络通信的程序,一般来说,建立服务器连接需要六个步骤。 #第一步:创建socket对象,调用socket 构造函数 import socket #socket=socket.socket(family,type) QQ_talk=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #第二步则是将 socket 绑定(指派)到指定地址上,socket.bind(address,port) QQ_talk.bind((\'192.168.100.149\',9000)) #address 是一个双元素元组((host,port)),主机名或者ip地址+端口号,如果端口号正在被使用或者保留,或者主机名IP地址错误,则引发socket.error异常。 #第三步:绑定后,必须准备好套接字,以便接受连接请求 QQ_talk.listen(2) #socket.listen(backlog) #backlog 指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求 #第四步:服务器套接字通过 socket的accept方法等待客户请求一个连接: conn,addr=QQ_talk.accept() #调用accept 方法时,socket会进入‘waiting’(或阻塞)状态,客户请求连接时,方法建立连接并返回服务器accept 方法 返回一个含有两个元素的元组,形如(conn,addr),第一个元素conn是新的socket对象,服务器通过它与客户通信,第二个元素(addr)是客户的internet地址 #等于 conn 是一个新对象new object包括地址和端口, addr是客户的IP地址 #第五步是处理阶段,服务器和客户通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息,send方法返回已发送的字符上数,服务器使用 recv方法从客户接受信息,调用recv 时,必须指定一个整数亚控制本次调用所接受的最大数据量。 recv方法在接受数据时会进入\'blocket\' 状态,最后返回一个字符串,用它来表示收到的数据,如果发送的量超过recv所允许,数据会被截断,多余的数据将缓冲于接受以后调用recv时,多余的数据会从缓冲区删除。 client_data=conn.recv(1024) conn.send(\'copy\') #第六步:传输结束,服务器调用socket的close方法以关闭连接 QQ_talk.close()
客户端 建立连接 需要4个步骤
#简单客户连接则需要4个步骤: #第一步: 创建一个socket对象以连接服务器 socket=socket.socket(famaily,type) import socket QQ_talk=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #第二步:使用socket的 connect方法连接服务器socket.conect((host,port)) conn,addr=QQ_talk.connect((\'192.168.100.149\',9090)) #第三步:客户和服务器通过send和recv方法通信。 server_data=QQ_talk.recv() server_=QQ_talk.send(\'client copy\') #第四步:结束后,客户通过调用socket 的 close 方法来关闭连接 QQ_talk.close()
练习:
使用socket 完成远程执行linux端的命令
#!/usr/bin/env python #!-*- coding:utf-8 -*- import socket session=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # phone.connect((\'127.0.0.1\',8090)) #这个操作对应server的 accept session.connect((\'192.168.100.149\',9000)) #这个操作对应server的 accept while True: session.send(\'hostname \'.encode(\'utf-8\')) hostname=session.recv(1024) session.send(\'who am i\'.encode(\'utf-8\')) username=session.recv(1024) # print(username.decode(\'utf-8\').split()[0]) msg=input(\'%s@%s# \'%(username.decode(\'utf-8\').split()[0],hostname.decode(\'utf-8\').strip())).strip() if not msg: continue session.send(msg.encode(\'utf-8\')) #这个操作对应server 的recv data=session.recv(1024) #对应server的send print(data.decode(\'utf-8\')) #打印server send过来的 信息 session.close()
server 端
#!/usr/bin/env python #!-*- coding:utf-8 -*- import socket,subprocess,os session=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #phone.bind((\'192.168.100.149\',8080)) session.bind((\'192.168.100.149\',9000)) session.listen(5) while True: conn,addr=session.accept() # print(\'client is \',conn) print(\'========Host: \',addr) while True: try: data=conn.recv(1024) if not data:break print(\'client send info: \',data) # if len(data)>=2: # os.system(data) # else: # data=\'\'.join(data) res=subprocess.Popen(data,shell=True,stdout=subprocess.PIPE) res_cmd=res.stdout.read() #if not res_cmd: #os.system(data) conn.send(res_cmd) except Exception: break conn.close() sess.close()
客户端 :
服务端:
socketserver 实现并发
介绍:
socketserver 实现并发
在之前学习中,服务端的第一个特点是:
1、一直运行提供服务(链接循环)基于一个连接的通信循环
2、要解决的就是连接循环和通信循环
这两个要求在之前的程序中都没有实现。现在需要通过socketserver实现并发
为什么使用:
在访问百度的时候,百度的服务器不只服务于你一个用户的吧, 百度服务器同时在服务N个 多个用户的访问
服务端使用:
import socketserver class Ftpserver(socketserver.BaseRequestHandler): # 要用就是这种形式,必须这样写, 这里解决的是通信 def handle(self): print(self) print(self.request) # 拿到的是conn while True: data=self.request.recv(1024) print(data) self.request.send(data.upper()) if if __name__ == \'__main__\': obj=socketserver.ThreadingTCPServer((\'192.168.100.149\',9000),Ftpserver) #线程 obj.serve_forever() #连接循环 等于多份accept()
如何用:
多个客户端访问服务端 ,已经实现并发
完整代码剖析:
基于udp 套接字: UDP是无连接
server 端
import socket udpserver=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) udpserver.bind((\'192.168.100.149\',9000)) while True: data=udpserver.recvfrom(1024) print(data)
client 端
import socket udpclient=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # udpclient.connect((\'192.168.100.149\',9000)) udpserver=(\'192.168.100.149\',9000) while True: inp=input(\'>>>>: \').strip() udpclient.sendto(inp.encode(\'utf-8\'),udpserver)
换种写法来实现:
server 端
import socket class recvdata: def __init__(self,pro_ipaddr,pro_port): self.pro_ipaddr=pro_ipaddr self.pro_port=pro_port def process(self): while True: auth_obj = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) auth_obj.bind((self.pro_ipaddr,self.pro_port)) client_data,client_addr=auth_obj.recvfrom(1024) print(client_data.decode(\'utf-8\').split(),client_addr) auth_obj.sendto(client_data,client_addr) server=recvdata(\'127.0.0.1\',9000) server.process()
client端:
import socket auth=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) authserver=(\'127.0.0.1\',9000) while True: msg=input(\'>>>>>: \') auth.sendto(msg.encode(\'utf-8\'),authserver) msg,addr = auth.recvfrom(1024) print(msg.decode(\'utf-8\').split())
效果:
服务端
多个客户端:
以上是关于socket 编程的主要内容,如果未能解决你的问题,请参考以下文章