python第八周项目_python第八周:socket网络编程

1.socket网络编程

1.1概念:

网络套接字是跨计算机网络的连接的端点。今天,计算机之间的大多数通信都基于互联网协议;因此大多数网络套接字都是Internet套接字。更准确地说,套接字是一个句柄(抽象引用),本地程序可以将其传递给网络应用程序编程接口(API)以使用该连接,例如“在此套接字上发送此数据”。

例如,发送“Hello,world!”通过TCP到地址为1.2.3.4的主机的端口80,可以获得一个套接字,将其连接到远程主机,发送字符串,然后关闭套接字。

实现一个socket至少要分以下几步,(伪代码):

套接字API是一种应用程序编程接口(API),通常由操作系统提供,允许应用程序控制和使用网络套接字。 Internet套接字API通常基于Berkeley套接字标准。在Berkeley套接字标准中,套接字是文件描述符(文件句柄)的一种形式,由于Unix哲学“一切都是文件”,以及套接字和文件之间的类比:你可以读,写,打开和关闭。

套接字地址是IP地址和端口号的组合,很像电话连接的一端是电话号码和特定分机的组合。 套接字不需要有地址(例如仅用于发送数据),但如果程序将套接字绑定到地址,则套接字可用于接收发送到该地址的数据。 基于此地址,Internet套接字将传入的数据包传递到适当的应用程序进程或线程

Socket Families(地址簇)

socket.AF_UNIX unix本机进程间通信

socket.AF_INET IPV4

socket.AF_INET6  IPV6

这些常量表示用于socket()的第一个参数的地址(和协议)系列。 如果未定义AF_UNIX常量,则不支持此协议。 根据系统的不同,可能会有更多常量可用。

Socket Types

socket.SOCK_STREAM  #for tcp

socket.SOCK_DGRAM  #for udp

socket.SOCK_RAW   #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通

过IP_HDRINCL套接字选项由用户构造IP头。

socket.SOCK_RDM  #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。

SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。

socket.SOCK_SEQPACKET #废弃了

这些常量表示套接字类型,用于socket()的第二个参数。 根据系统的不同,可能会有更多常量可用。 (只有SOCK_STREAM和SOCK_DGRAM似乎通常很有用。)

1.2 Socket 参数

(1)socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)  必会

使用给定的地址系列,套接字类型和协议号创建一个新套接字。 地址族应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 套接字类型应该是SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或者其他SOCK_常量之一。 协议号通常为零并且可以省略,或者在地址族是AF_CAN的情况下,协议应该是CAN_RAW或CAN_BCM之一。 如果指定了fileno,则忽略其他参数,从而返回具有指定文件描述符的套接字。 与socket.fromfd()不同,fileno将返回相同的套接字而不是重复。 这可能有助于使用socket.close()关闭分离的套接字。

(2)socket.socketpair([family[, type[, proto]]])

使用给定的地址系列,套接字类型和协议编号构建一对连接的套接字对象。 地址族,套接字类型和协议号与上面的socket()函数相同。 如果在平台上定义,则默认系列为AF_UNIX; 否则,默认为AF_INET。

(3)socket.create_connection(address[, timeout[, source_address]])

连接到侦听Internet地址(2元组(主机,端口))的TCP服务,并返回套接字对象。 这是一个比socket.connect()更高级的函数:如果host是非数字主机名,它将尝试为AF_INET和AF_INET6解析它,然后尝试依次连接到所有可能的地址,直到连接成功。 这样可以轻松编写与IPv4和IPv6兼容的客户端。

传递可选的timeout参数将在尝试连接之前设置套接字实例上的超时。 如果未提供超时,则使用getdefaulttimeout()返回的全局默认超时设置。

如果提供,则source_address必须是要连接的套接字的2元组(主机,端口)作为其源地址才能连接。 如果主机或端口分别为'或0,则将使用OS默认行为。

(4)socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) #获取要连接的对端主机地址

(5)sk.bind(address) 必会

sk.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

(6) sk.listen(backlog) 必会

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5。这个值不能无限大,因为要在内核中维护连接队列

(7)sk.setblocking(bool) 必会

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

(8) sk.accept() 必会

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来

(9)sk.connect(address) 必会

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

(10)sk.connect_ex(address)

同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

(11)sk.close() 必会

关闭套接字

(12)sk.recv(bufsize[,flag])必会

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

(13)sk.recvfrom(bufsize[.flag])

与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

(14)sk.send(string[,flag]) 必会

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

(15)sk.sendall(string[,flag]) 必会

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。

(16)sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

(17)sk.settimeout(timeout) 必会

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

(18)sk.getpeername()  必会

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

(19)sk.getsockname()

返回套接字自己的地址。通常是一个元组(ipaddr,port)

(20)sk.fileno()

套接字的文件描述符

(21)socket.sendfile(file, offset=0, count=None)

发送文件 ,但目前多数情况下并无什么卵用。

1.3 通过socket实现简单的ssh

程序流程如下:

程序代码:

socket_server端:

importsocket,os

server=socket.socket()

server.bind(("localhost",9999))

server.listen()whileTrue:

conn,addr= server.accept() #阻塞

whileTrue:print("wait for new cmd:")

cmd= conn.recv(1024).decode()if notcmd:print("客户端已断开")breakcmd_result=os.popen(cmd).read()if len(cmd_result) ==0:

cmd_result= "这条命令错误"length= len(cmd_result.encode("utf-8"))

length= len(cmd_result.encode("utf-8"))

conn.send(str(length).encode("utf-8"))

conn.recv(1024)

conn.send(cmd_result.encode("utf-8"))

server.close()

socket_client端:

importsocket

client=socket.socket()

client.connect(("localhost",9999))whileTrue:

cmd= input("输入指令:")if len(cmd) ==0:continueclient.send(cmd.encode("utf-8"))

length= client.recv(1024).decode()print("命令结果大小:",length)

receive_size=0

receive_data= b""client.send(b"OK")while receive_size

data= client.recv(1024)

receive_size+=len(data)

receive_data+=dataprint("命令结果实际大小:",receive_size)print(receive_data.decode())

client.close()

程序运行结果:

#server端:

wait fornew cmd:

ipconfig

waitfornew cmd:#client端:

输入指令:ipconfig

命令结果大小:1680命令结果实际大小:1680Windows IP 配置

以太网适配器 以太网:

媒体状态 . . . . . . . . . . . . : 媒体已断开连接

连接特定的 DNS 后缀 . . . . . . . :

无线局域网适配器 本地连接* 3:

媒体状态 . . . . . . . . . . . . : 媒体已断开连接

连接特定的 DNS 后缀 . . . . . . . :

无线局域网适配器 本地连接* 12:

媒体状态 . . . . . . . . . . . . : 媒体已断开连接

连接特定的 DNS 后缀 . . . . . . . :

以太网适配器 VMware Network Adapter VMnet1:

连接特定的 DNS 后缀 . . . . . . . :

本地链接 IPv6 地址. . . . . . . . : fe80::7ddd:a3e4:9673:512e%7IPv4 地址 . . . . . . . . . . . . :192.168.74.1子网掩码 . . . . . . . . . . . . :255.255.255.0默认网关. . . . . . . . . . . . . :

以太网适配器 VMware Network Adapter VMnet8:

连接特定的 DNS 后缀 . . . . . . . :

本地链接 IPv6 地址. . . . . . . . : fe80::4cc1:5dc2:37f:7e7b%17IPv4 地址 . . . . . . . . . . . . :192.168.43.1子网掩码 . . . . . . . . . . . . :255.255.255.0默认网关. . . . . . . . . . . . . :

无线局域网适配器 WLAN:

连接特定的 DNS 后缀 . . . . . . . :

IPv6 地址 . . . . . . . . . . . . :2001:da8:215:8f01:8d1d:db29:3fd2:c6d6

临时 IPv6 地址. . . . . . . . . . :2001:da8:215:8f01:dc75:865e:ccf6:e781

本地链接 IPv6 地址. . . . . . . . : fe80::8d1d:db29:3fd2:c6d6%10IPv4 地址 . . . . . . . . . . . . :10.122.252.64子网掩码 . . . . . . . . . . . . :255.255.192.0默认网关. . . . . . . . . . . . . : fe80::274:9cff:fe7d:fadb%10

10.122.192.1输入指令:

1.4 通过socket实现简单的ftp server

1.读取文件名

2.检测文件是否存在

3.打开文件

4.检测文件大小

5.发送文件大小和md5给客户端

6.等客户端确认

7.开始边读边发数据

8.md5

9.关闭文件

程序代码:

客户端:

#-*- coding:utf-8 -*-#!/user/bin/env.python#Author:Mr Wu

'''FTP Server'''

importsocket,os,hashlib

server=socket.socket()

server.bind(("localhost",1999))

server.listen()whileTrue:

conn,addr= server.accept() #阻塞

whileTrue:

data= conn.recv(1024).decode()if notdata:print("客户端已断开连接!")breakfile_cmd,file_name=data.split()ifos.path.isfile(file_name):

file_size=os.stat(file_name).st_size

conn.send(str(file_size).encode("utf-8"))

conn.recv(1024) #避免粘包

m =hashlib.md5()

f= open(file_name,"rb")print("开始发送文件.....")for line inf:

m.update(line)

conn.send(line)

f.close()print("发送md5.......")

conn.send(m.hexdigest().encode("utf-8"))

server.close()

服务端:

#-*- coding:utf-8 -*-#!/user/bin/env.python#Author:Mr Wu

importsocket,os,hashlib

client=socket.socket()

client.connect(("localhost",1999))whileTrue:

cmd= input("输入文件名[格式:get 文件名]>>>:").strip()if len(cmd) ==0:continue

if cmd.startswith("get"):

file_name= cmd.split()[1]

client.send(cmd.encode("utf-8"))

data= client.recv(1024)

file_total_size=int(data.decode())

client.send(b"OK")

file_size=0

f= open(file_name,"wb")

m=hashlib.md5()while file_size

last_size= file_total_size -file_sizeif last_size < 1024:

size=last_sizeelse:

size= 1024

'''避免粘包'''data=client.recv(size)

m.update(data)

f.write(data)

file_size=+len(data)

f.close()

md5=m.hexdigest()

received_md5= client.recv(1024).decode()if md5 ==received_md5:print("文件md5一致,传输成功!")else:print("文件传输错误!")else:print("输入格式错误!")continue

运行结果:

server端:

开始发送文件.....

发送md5.......

client端:

输入文件名[格式:get 文件名]>>>:get test.py

文件md5一致,传输成功!

2.socketServer的使用

2.0socketserver主要包含的类:

classsocketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

它使用Internet TCP协议,该协议在客户端和服务器之间提供连续的数据流。 如果bind_and_activate为true,

则构造函数会自动尝试调用server_bind()和server_activate()。 其他参数将传递给BaseServer基类。

classsocketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

这使用数据报,这些数据报是可能无序到达或在传输过程中丢失的离散信息包。 参数与TCPServer相同。

classsocketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)

classsocketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)

这些不经常使用的类类似于TCP和UDP类,但使用Unix域套接字; 它们不适用于非Unix平台。 参数与TCPServer相同。

这四个类同步处理请求; 必须在下一个请求开始之前完成每个请求。 如果每个请求需要很长时间才能完成,这是不合适的,

因为它需要大量计算,或者因为它返回了客户端处理速度慢的大量数据。 解决方案是创建一个单独的进程或线程来处理每个请求;

ForkingMixIn和ThreadingMixIn混合类可用于支持异步行为。

继承图中有五个类,其中四个代表四种类型的同步服务器:

2.1 使用方法:

(1)你必须自己创建一个处理类,并且这个类要继承BaseRequestHandler,并且还要重写父类里的handle()

(2)你必须实例化TCPServer,并且传递server ip和你上面创建的请求处理类给这个TCPServer

(3)server.handle_request() #只处理一个请求

server.serve_forever() #处理多个连接请求,永远执行

2.2 SocketServer程序示例:

#-*- coding:utf-8 -*-#!/user/bin/env.python#Author:Mr Wu

importsocketserverclassMyTCPHandler(socketserver.BaseRequestHandler):'''每一个请求过来都会实例化MyTCPHandler'''

defhandle(self):'''与客户端所有的交互都是在handle里完成的'''

whileTrue:try:

self.data= self.request.recv(1024).strip()print("{} wrote:".format(self.client_address[0]))print(self.data)#if not self.data:

#print("客户端断开连接")

#break

#just send the same data,but upper-cased

self.request.send(self.data.upper())exceptConnectionResetError as e:print(e)break

if __name__ == "__main__":

HOST,PORT= "localhost",9999

#create the server,binding to localhost on port 9999

server =socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)'''activate the server:this will keep running until you

interrupt the program with Ctrl-C'''server.serve_forever()#处理多个请求,即可以连接多个客户端

未完待续。。。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于C++&OPENCV 的全景图像拼接 C++是一种广泛使用的编程语言,它是由Bjarne Stroustrup于1979年在新泽西州美利山贝尔实验室开始设计开发的。C++是C语言的扩展,旨在提供更强大的编程能力,包括面向对象编程和泛型编程的支持。C++支持数据封装、继承和多态等面向对象编程的特性和泛型编程的模板,以及丰富的标准库,提供了大量的数据结构和算法,极大地提高了开发效率。12 C++是一种静态类型的、编译式的、通用的、大小写敏感的编程语言,它综合了高级语言和低级语言的特点。C++的语法与C语言非常相似,但增加了许多面向对象编程的特性,如类、对象、封装、继承和多态等。这使得C++既保持了C语言的低级特性,如直接访问硬件的能力,又提供了高级语言的特性,如数据封装和代码重用。13 C++的应用领域非常广泛,包括但不限于教育、系统开发、游戏开发、嵌入式系统、工业和商业应用、科研和高性能计算等领域。在教育领域,C++因其结构化和面向对象的特性,常被选为计算机科学和工程专业的入门编程语言。在系统开发领域,C++因其高效性和灵活性,经常被作为开发语言。游戏开发领域中,C++由于其高效性和广泛应用,在开发高性能游戏和游戏引擎中扮演着重要角色。在嵌入式系统领域,C++的高效和灵活性使其成为理想选择。此外,C++还广泛应用于桌面应用、Web浏览器、操作系统、编译器、媒体应用程序、数据库引擎、医疗工程和机器人等领域。16 学习C++的关键是理解其核心概念和编程风格,而不是过于深入技术细节。C++支持多种编程风格,每种风格都能有效地保证运行时间效率和空间效率。因此,无论是初学者还是经验丰富的程序员,都可以通过C++来设计和实现新系统或维护旧系统。3

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值