使用python搭建Socket服务器
#coding utf-8
import socket全双工
socket.AF_INET #IPv4版本
socket.SOCK_DGRAM #是udp
socket.SOCK_STREAM #是tcp
#设置当服务器先close 保证下次运行程序可以立即使用端口
.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
3次握手操作
- 客户端发起链接syn
- 服务器回应ack并发起syn
- 客户端回应ack
4次挥手操作,一般由客户端发起关闭
- 客户端发起关闭‘发送’
- 服务器回应接收到
- 服务器发起关闭‘接收’
- 客户端回应接收到,并等待一段时间(2-5min)释放资源,又叫2msl两倍等待释放
-
udp不区分服务器与客户端
socket
创建套接字
bind
绑定IP和port
sendto/recvfrom
发送/接收数据.recvfrom(1024)
如果没有数据会造成阻塞
close
关闭套接字 -
tcp客户端
socket
创建套接字
connect
链接服务器
send/recv
发送/接收数据
close
关闭套接字 -
tcp服务器
socket
创建套接字
bind
绑定IP和port
listen
被动接收模式
accept
接收客户端链接地址
recv/send
接收/发送数据
close
关闭套接字
.listen(128)
被动模式 128代表同一时间可以处理的链接数量
.accept()
接收数据
字符串前面添加b就可以转化成字节,如:b‘hhhsdf’
变量.encode("utf-8")
转化任意编码成字节,如:abc.encode("utf-8")
Windows默认使用gbk编码发送消息
socket模拟服务器处理响应
所有的linux里面的东西都对应一个文件
fd文件描述符,就是一个数字,对应一个特殊的文件,例如网络接口
- 主进程中等待socket,启用进程处理链接的同时应当继续调用
socket.close()
;多线程/协程都不需要在主线程中调用socket.close()
-
socket.setblocking(False)
设置套接字为非堵塞的方式
#非阻塞链接
tcp_server = socket(···)
tcp_server.setblocking(False) # 设置套接字为非堵塞的方式
client_socket_list = list()
while True:
try:
new_socket, new_address = tcp_server.accept()
except Exception as ret:
print(“——-没有新的客户的客户端到来——”)
else:
print(“—-只要没有异常,那么就意味着 来了一个新的客户大u呢——-”)
new_socket.setblocking(False)
client_socket_list.append(new_socket)
for client_socket in client_socket_list:
try:
recv_data = client_socet.recv(1024)
except Exception as ret:
print(“——这个客户端没有发送过来数据——”)
else:
if recv_data:
print(“——客户端发送过来了数据——”)
else:
client_socket.close()
client_socket_list.remove(client_socket)
- 处理客户端请求数据的响应中增加
Content-Length:body内容长度
来告诉浏览器资源响应完毕,实现长链接
常用Linux命令
ps -aux
查看所有进程
kill 进程ID
可以杀死指定进程
sudo dhclient
管理员桥接网络设置,将虚拟机IP网段与本机保持一致
mkdir 文件夹
创建目录
touch 文件名
创建指定文件名的文件
ls
查看当前目录下的文件或文件夹
ls -a
包含隐藏文件.开头的文件就是隐藏的
cp 当前文件
目标文件 拷贝当前文件到目标文件(自动创建目标文件)
mv
修改目标文件名称
cat
查看指定文件内容
tail -f
持续查看文件内容
常用方法
- 在方法中修改全部变量时,如果使用赋值= ,需要在方法中提前声明
global变量
-
print("\r拷贝进度:%.2f" % (2*100/123),end="")
实现单行输出 -
help(对象名)
获取对象帮助信息 -
range(10)
自动生成10以内列表
from collections import Iterator/Iterable迭代器
from collections import Iterable
isinstance(验证对象,Iterable)
返回True表示可以迭代
特性/伪协程
- 节省内存空间,因为不会立刻计算
-
[x*2 for x in range(10)]
只是列表(x*2 for x in range(10))
这样返回的就是一个可迭代对象 - 包含
yield
方法就会变成迭代,执行一部分就直接返回数据 - 可以暂停代码,在yield语句位置
-
form greenlet import greenlet
封装来yield的实现greenlet(普通方法名)
方法中不再需要出现yield实现协程效果
- 一个普通对象如果要实现迭代功能需要实现:
def __iter__(self):
返回自身;def __next__(self):
返回每次要取的值 -
raise StopIteration
结束迭代 -
next(对象)
获得下一个值 -
.send(参数)
可迭代中修改对象的返回值,需要在next后使用,否则参数只能是None
import multiprocessing进程
-
.Process
创建进程对象 -
.Queue
创建队列,.put()
添加数据,.get()
获取一条数据没有会等待,.get_nowait()
不等待取数据,.full()
队列是否满了,.empty()
队列是否空了 -
.Pool(3)
定义一个进程池,.apply_async( 方法名,参数)
空闲子进程调用方法,.join()
等待close后 结束进程池 -
.Manager().Queue()
可传递到进程池
import threading线程
-
threading.Thread(target=方法名,args=参数)
将指定方法添加到多任务中,参数是元组 -
.start()
开始执行多任务 -
.enumerate()
获得已有线程列表 -
.Lock()
创建线程锁,返回锁对象.acquire()
上锁,.release()
解锁
import gevent协程
只有遇到延时操作会自动切换协程,否则只会顺序执行
geven是对 greenlet的封装,greenlet是对yield的封装
-
gevent.spawn(方法,方法参数)
创建一个协程对象 -
gevent.getcurrent()
获得当前运行的协程对象 -
gevent.sleep(1)
休息一秒 -
.join()
等待协程运行gevent.joinall([gevent对象])
多个等待 -
gevent.monkey.patch_all()
程序中用到time语法的耗时操作,转换成gevent中自己实现的模块
import os 文件操作
-
.mkdir
创建文件夹 -
.listdir
获得文件夹下的所有文件列表 -
with open('','wb')
保证文件会自动关闭
import urllib网络请求
-
urllib.request.urlopen(‘网址’).read()
获得响应数据流
import re正则
通用正则
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n) |
[] | 匹配[]中列举的字符 |
\d | 匹配数字0-9 |
\D | 匹配非数字 |
\s | 匹配空白 空格 tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符a-z A-Z 0-9 _ 汉字 |
\W | 匹配非单词字符 |
—- | 多次匹配⬇️ |
* | 匹配前一个字符出现0或无限次 |
+ | 匹配前一个字符出现1或无限次 |
? | 匹配前一个字符出现1或0次 |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
—— | 开始结束⬇️ |
^ | 匹配字符串开始 |
$ | 匹配字符串结尾 |
— | 匹配分组⬇️ |
匹配左右任意一个字符 | |
(abc) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?p<name>) | 分组起别名 |
(?p=nam) | 引用别名为name分组匹配到的字符串 |
-
[a-zA-Z0-9_]{4,20}@163\.com$
一个邮箱正则,大小写字母数字下划线 长度4-20 @163.com结尾 -
<(\w*)>.*</\1>
\num的用法\1代表前面分组中的值如<h1></h1>
re模块高级用法
-
re.match(r”正则”,用户输入多字符串或列表)
获得所有匹配对象 -
re.search(r”正则”,字符串或列表)
匹配到就结束 -
.group()
返回所有匹配值 -
re.findall()
搜索所有匹配 列表 -
re.sub(r正则,替换值,用户输入字符串)
将匹配到的数据进行替换,返回替换后的值;替换值可以是一个函数 -
re.split(r”:| ”,用户输入的字符串)
使用冒号或空格切割并返回一个列表
import random随机
.choice(列表)
随机获取一个值