python统计字符串中数字个数 socket_Python29 Socket1

socket 基本信息

socket 封装了TCP/IP、UDP、FTP、SSH、DHCP等多个协议。

由于socket封装了TCP/IP所以在建立连接的时候,不需要手动去写三次握手/四次握手等代码。

socket IP地址

socket.AF_INET 表示IPV4

socket.AF_INET6 表示IPV6

socket 类型

socket.SOCK_STREAM # tcp协议

socket.SOCK_DGRAM # udp协议

socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

可以使用socket.SOCK_RAW伪造IP,来发起泛洪***

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

socket实例

socket.socket()用于声明协议类型

我们按住ctrl键点第二个socket可以看到下面的内容

可以看到family表示地址簇,AF_INET表示ipv4; SOCK_STREAM表示TCP; 后面的内容暂时无需了解;

在socket.socket()这个括号中不指定协议,默认就是IPV4和TCP

客户端:

import socket

client = socket.socket() #声明socket类型,同时生成socket连接对象

client.connect(('localhost',6969)) #设置连接的目标,因为括号中只能写一个元素,所以这里将组ip(localhost)和端口6969两个元素写在一个元组中。

client.send(b'Hello World!') #发送数据;在python2中允许发送字符串和字节,但是在python3中只能发送字节(bytes)类型,所以前面的b就是将其转换数据类型为字节

data = client.recv(1024) #让客户端可以接收数据,这里值允许接收1024字节;官方建议最大写8192。

print ('recv:',data) #打印接收到的数据

client.close() #关闭连接

可以看到在括号中只允许填写一个address元素,所以只能通过元组的方式将多个元素写入。

服务器端:

import socket

server = socket.socket()

server.bind(('localhost',6969)) #绑定要监听的端口

server.listen() #开始监听,括号中可以设置监听挂起的client数量,默认不限制。

print ('等待接收数据......')

conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...

#accept会返回两个值,第一个是连接的标记位(这里赋值给conn),然后#conn就是客户端链接过来而在服务器端为其生成的一个连接实例,多个客户端连接服务器就是对个实例;第二个是对方的地址(这里赋值给addr)

print (conn,addr)

print ('数据来了!')

data = conn.recv(1024) #让这个实例,接收数据

print ('recv:',data)

conn.send(data.upper()) #让这个实例返回数据(大写的形式)

server.close() #服务器关闭的话就是这整个服务器关闭,而不是针对实例关闭,所以这里还是要使用server.close(),而不是conn.close()。

执行服务器:先执行服务器端的代码,因为服务器需要进行监听

执行客户端:

上图是执行客户端后,客户端收到的代码,可以看到是服务器已大写的形式,将数据返回给客户端

上图是执行客户端后服务器看到的结果

print (conn)看到的是:

print (addr)看到的结果是:('127.0.0.1', 56413) #这个56413是随机的源端口

print ('recv:',data)的结果是:recv: b'Hello World!' #从客户端接收到的数据

client.send(b'Hello World!') #通过b可以将数据转成字节,但是这里只能转ASCII码,如果转中文就会报错。

client.send('测试测试!'.encode('utf-8')) #通过encode来转码中文

上图是print中文的结果,因为是utf-8所以不能正常显示,需要进行decode才可以

print ('recv:',data.decode()) #decode(),默认给解码成unicode,所以不用指定编码

执行结果:

recv: 测试测试!

#解码后可以正常看print的中文数据。

实现多次重复发送和接收

之前的代码只能实现一次的发送和接收,那么接下来实现多次发送和接收。

客户端:

import socket

client = socket.socket()

client.connect(('localhost',6969))

while True: #循环,可以使客户端多次发送数据

info = input('>>:').strip()

client.send(info.encode('utf-8'))

data = client.recv(1024)

print ('recv:',data.decode())

client.close()

服务器端:

import socket

server = socket.socket()

server.bind(('localhost',6969))

server.listen()

print ('等待接收数据......')

while True:

conn,addr = server.accept()

print (conn,addr)

print ('数据来了!')

data = conn.recv(1024)

print ('recv:',data)

conn.send(data.upper())

server.close()

先运行服务器端来监听

上图客户端输入数据

上图服务器收到的数据

上图客户端输入第二个数据时就卡主了

上图可以看到服务器没有收到客户端第二次发送的数据,服务器端也卡主了。

此时客户端1的连接并没有断开

上图是再次运行客户端建立一个新的连接

上图可以看到新连接的数据

上图是之前的连接,可以看到已经关闭了,表示当前服务器端只能接收会话一个连接的数据(当前先不实现多连接,先实现反复的发送和接收数据)

修改服务器端代码:

import socket

server = socket.socket()

server.bind(('localhost',6969))

server.listen()

print ('等待接收数据......')

conn, addr = server.accept() #将实例移出while循环,这样就不会重复的去建立实例,而是通过一个实例(连接)来反复的发送数据。

#如果该代码还在while中,那么每一次循环都会建立一个新连接,等发送一次数据后,又新建连接,那么之前的连接就不能再发送数据了,只能通过新的连接发送数据。

print(conn, addr)

print('数据来了!')

while True:

data = conn.recv(1024)

print ('recv:',data.decode())

conn.send(data.upper())

server.close()

上图是客户端发送的数据

上图是服务器收到的数据

已经实现了客户端与服务器的多次数据交互。

客户端点击停止来断开连接

在服务器端也断开了

在linux中和Windows中断开连接时是有区别的,下面在linux执行上面的客户端和服务器代码

在linux中服务器正在接收和返回数据

上图在linux中客户端正在发送和接收返回的数据

当停止客户端的连接后,服务器端一直在不断的recv空的数据,进入死循环一直在刷屏;

修改一下服务器端的代码:

import socket

server = socket.socket()

server.bind(('localhost',6969))

server.listen()

print ('等待接收数据......')

conn, addr = server.accept()

print(conn, addr)

print('数据来了!')

count = 0 #设置一个计数器

while True:

data = conn.recv(1024)

print ('recv:',data.decode())

conn.send(data.upper())

count += 1 #每循环一次+1

if count > 10:break #当大于10时,断开

server.close()

然后下面我们在继续看代码的执行情况

客户端发送和接收数据

上图统计已大于10,所以会自动停止。

修改服务器端代码:

import socket

server = socket.socket()

server.bind(('localhost',6969))

server.listen()

print ('等待接收数据......')

conn, addr = server.accept()

print(conn, addr)

print('数据来了!')

count = 0

while True:

data = conn.recv(1024)

print ('recv:',data.decode())

if not data: #设立data不为真(也就是空),执行条件下的语句

print ('client has lost...')

break

conn.send(data.upper())

count += 1

if count > 10:break

server.close()

服务器端匹配了if not data的条件,然后就break循环了。

连接断开后客户端和服务器的程序就都结束了。

修改服务器端代码:让其当断开连接后,客户端可以随时建立连接发送数据,那么服务器端随时监听

import socket

server = socket.socket()

server.bind(('localhost', 6969))

server.listen()

print('等待接收数据......')

while True:

conn, addr = server.accept()

print(conn, addr)

print('数据来了!')

while True:

data = conn.recv(1024)

print('recv:', data.decode())

if not data:

print("client has lost...")

break #这里断开连接就跳出当前循环,到外面的while循环,通过conn, addr = server.accept()可以建立新的连接然后再次发送数据

conn.send(data.upper())

server.close()

client1的执行结果:

test@test-virtual-machine:~$ python3 桌面/A1.py hey

>>:1

recv: 1

>>:2

recv: 2

>>:3

recv: 3

>>:4

recv: 4

>>:5

recv: 5

>>:

server端的结果:

test@test-virtual-machine:~$ python3 桌面/A2.py

等待接收数据......

('127.0.0.1', 32826)

数据来了!

recv: 1

recv: 2

recv: 3

recv: 4

recv: 5

此时client1的连接先不断开,然后在新启一个连接模拟client2

client2:

test@test-virtual-machine:~$ python3 桌面/A1.py

>>:1

#client2 发送数据后就卡主了(卡主表示当前client2的连接被挂起了),且当前server端也没有接收到来自client2的数据。

client1:

ctrl+c断开连接

server端:

test@test-virtual-machine:~$ python3 桌面/A2.py

等待接收数据......

('127.0.0.1', 32826)

数据来了!

recv: 1

recv: 2

recv: 3

recv: 4

recv: 5

recv:

client has lost... #此处表示client1已经断开连接了

('127.0.0.1', 32828)

数据来了!

recv: 1

#这里可以看到当client1断开连接后,挂起的client2立刻建立好连接,然后并接收到了来自client2的数据

#现在client2就可以与server不断的交互了。

当一个连接正在与server交互时,其他的连接就要被挂起等待,那么同时可以挂起几个连接呢?

server.listen(5) #在括号中定义数字,5就表示同一时间可以挂起5个连接

#不过当前的代码逻辑还实现不了,需要以后在使用异步的时候可以实现

修改客户端代码:

import socket

client = socket.socket()

client.connect(('localhost',6969))

while True: #循环,可以使客户端多次发送数据

info = input('>>:').strip()

if len(info) == 0:continue #目前有个问题当客户端什么数据都不填写,直接回车,就会卡主,所以这里要定义一个条件当数据为0时,继续下次循环

client.send(info.encode('utf-8'))

data = client.recv(1024)

print ('recv:',data.decode())

client.close()

客户端这里直接回车后,没有卡主,而是让你重新输入数据

通过命令获取远程服务器执行结果

客户端:

import socket

client = socket.socket()

client.connect(('localhost',6969))

while True: #循环,可以使客户端多次发送数据

info = input('>>:').strip()

if len(info) == 0:continue

client.send(info.encode('utf-8'))

data = client.recv(1024)

print (data.decode())

client.close()

服务器端:

import socket

import os

server = socket.socket()

server.bind(('localhost', 6969))

server.listen()

print('等待接收数据......')

while True:

conn, addr = server.accept()

print("新连接:", addr)

while True:

data = conn.recv(1024)

if not data:

print("client has lost...")

break

print('recv:', data.decode())

res = os.popen(data.decode()).read() #因为发送过来的是字节,但系统不识别这个字节命令,所以要解码成字符串命令,系统才能识别

conn.send(res.encode('utf-8')) #将结果编码后在发送过去,客户端相应的查看结果也要解码

server.close()

执行结果:

服务器端:

test@test-virtual-machine:~$ python3 桌面/A2.py

等待接收数据......

('127.0.0.1', 58682)

数据来了!

recv: df

客户端:

test@test-virtual-machine:~$ python3 桌面/A1.py

>>:df

文件系统 1K-块 已用 可用 已用% 挂载点

udev 991244 0 991244 0% /dev

tmpfs 203072 6492 196580 4% /run

/dev/sda1 19478204 5194164 13271560 29% /

tmpfs 1015344 124 1015220 1% /dev/shm

tmpfs 5120 0 5120 0% /run/lock

tmpfs 1015344 0 1015344 0% /sys/fs/cgroup

tmpfs 203072 64 203008 1% /run/user/1000

/dev/sr0 1511808 1511808 0 100% /media/test/Ubuntu-Kylin 16.04 LTS amd64

#可以看到成功的通过执行df命令,并将结果返回

>>:top

#客户端执行不了这种动态的命令,因为这个内容一直在变动。不想df执行完成后将结果返回。

>>:top -bn 1 #只显示1秒钟的数据,接下来不在更新了,所以可以给返回

top - 22:11:43 up 1:24, 4 users, load average: 0.00, 0.01, 0.05

Tasks: 292 total, 1 running, 290 sleeping, 0 stopped, 1 zombie

%Cpu(s): 0.4 us, 0.5 sy, 0.0 ni, 98.4 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st

KiB Mem : 2030688 total, 157464 free, 995464 used, 877760 buff/cache

KiB Swap: 1046524 total, 1046524 free, 0 used. 955516 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

3689 test 20 0 43672 3664 3056 R 6.7 0.2 0:00.01 top

1 root 20 0 185100 5656 3916 S 0.0 0.3 0:02.19 systemd

2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd

3 root 20 0 0 0 0 S 0.0 0.0 0:00.04 ksoftirqd/0

5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H

7 root 20 0 0 0 0 S 0.0 0.0 0:06.82 rcu_sched

8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh

9 root rt 0 0

>>:

#通过结果可以看到内容并没有显示全,这是因为设置了字节为1024的原因; 剩下没有显示的内容,会等你再次执行命令(任何命令)后,会发送过来,因为没显示的数据已经被换成了,只能等待下次发送。

将客户端的代码修改:data = client.recv(102400) #改成102400然后在测试

客户端:

>>:top -bn 1

top - 22:19:25 up 1:32, 4 users, load average: 0.00, 0.01, 0.05

Tasks: 292 total, 1 running, 290 sleeping, 0 stopped, 1 zombie

%Cpu(s): 0.4 us, 0.5 sy, 0.0 ni, 98.5 id, 0.6 wa, 0.0 hi, 0.0 si, 0.0 st

KiB Mem : 2030688 total, 156592 free, 996028 used, 878068 buff/cache

KiB Swap: 1046524 total, 1046524 free, 0 used. 954876 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

1535 test 20 0 44152 4516 2820 S 6.2 0.2 0:05.52 dbus-daemon

3743 test 20 0 43672 3616 3008 R 6.2 0.2 0:00.01 top

1 root 20 0 185100 5656 3916 S 0.0 0.3 0:02.22 systemd

2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd

3 root 20 0 0 0 0 S 0.0 0.0 0:00.04 ksoftirqd/0

5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H

7 root 20 0 0 0 0 S 0.0 0.0 0:07.14 rcu_sched

8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh

9 root rt 0 0 0 0 S 0.0 0.0 0:00.01 migration/0

10 root rt 0 0 0 0 S 0.0 0.0 0:00.04 watchdog/0

11 root rt 0 0 0 0 S 0.0 0.0 0:00.04 watchdog/1

12 root rt 0 0 0 0 S 0.0 0.0 0:00.01 migration/1

13 root 20 0 0 0 0 S 0.0 0.0 0:00.10 ksoftirqd/1

15 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/1:0H

16 root rt 0 0 0 0 S 0.0 0.0 0:00.04 watchdog/2

17 root rt 0 0 0 0 S 0.0 0.0 0:00.01 migration/2

#可以看到一下就将结果都显示出来了,只不过因为太长,这里没有全部粘贴过来。

下面代码示例传输文件:

客户端:

import socket

client = socket.socket()

client.connect(('localhost',6969))

f = open('test123123.txt','w') #打开一个新文件(原来不存在),将服务器端发送过来的数据,写在这个新建的test123123.txt文件中;在while外面打开文件,以免每次循环时都重新打开文件。

while True: #循环,可以使客户端多次发送数据

info = input('>>:').strip()

if len(info) == 0:continue

client.send(info.encode('utf-8'))

data = client.recv(102400000) # 设置可以一次收最大100M

f.write(data.decode()) # 发送过来的数据是utf-8,需要decode成unicode(这里要注意:linux系统数据格式默认就是utf-8,所以直接data.decode()是没问题的,但如果是Windows,那么就需要data.decode(gbk))

f.flush() # 写入后需要更新内容

client.close()

服务器端:

import socket

server = socket.socket()

#不加下面代码,重复执行代码时会报错,显示address used,表示地址正在使用;因为代码执行结束时系统的进程可能还在挂着,所以再次执行代码时,没法复用地址,所以下面的代码就是允许复用地址。

server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

server.bind(('localhost', 6969))

server.listen()

print('等待接收数据......')

while True:

conn, addr = server.accept()

print("新连接:", addr)

while True:

data = conn.recv(1024)

if not data:

print("client has lost...")

break

print('recv:', data.decode())

f = open('test1.txt','r')

data = f.read()

print (len(data))

conn.sendall(data.encode('utf-8'))

server.close()

上图为test1.txt文件中的内容;

上图为客户端读取服务器发送过来的数据后,新建的test123123.txt文档,可以看到数据内容相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值