Socket
udp收发
import socket
# family:
# socket.AF_UNIX == 只能够用于单一的Unix系统进程间通信
# socket.AF_INET == 服务器之间网络通信
# socket.AF_INET6 == IPv6
# type:
# socket.SOCK_STREAM == 流式socket , for TCP
# socket.SOCK_DGRAM == 数据报式socket , for UDP
# socket.SOCK_RAW == 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文
# 创建socket
family = socket.AF_INET
type_ = socket.SOCK_DGRAM
s = socket.socket(family, type_)
# 发送数据到指定ip地址的指定端口
data = 'hello'.encode('utf8')
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.sendto(data, address)
# 关闭socket
s.close()
import socket
# 创建socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 在指定端口接收数据,ip地址为本机地址
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.bind(address)
# 接收数据
data, (from_ip, from_port) = s.recvfrom(1024)
print('从{}地址{}端口号接受到消息,内容是{}'.format(from_ip, from_port, data.decode('utf8')))
# 关闭socket
s.close()
tcp收发
import socket
# 创建socket
family = socket.AF_INET
type_ = socket.SOCK_STREAM
s = socket.socket(family, type_)
# 绑定端口
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.bind(address)
# 把socket变成一个被动监听的socket
s.listen(128)
# 接收数据
client_socket, (client_ip, client_port) = s.accept()
data = client_socket.recv(1024)
print(data.decode('utf8'))
# 关闭socket
s.close()
import socket
# 创建socket
family = socket.AF_INET
type_ = socket.SOCK_STREAM
s = socket.socket(family, type_)
# 在发送数据之前,先与服务器进行连接
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.connect(address)
# 发送数据
data = 'hello'.encode('utf8')
s.send(data)
# 关闭socket
s.close()
文件收发
import socket
import os
# 创建socket
family = socket.AF_INET
type_ = socket.SOCK_STREAM
s = socket.socket(family, type_)
# 绑定端口
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.bind(address)
# 把socket变成一个被动监听的socket
s.listen(128)
# 接收文件名
client_socket, (client_ip, client_port) = s.accept()
file_name = client_socket.recv(3000).decode('utf8')
if os.path.isfile(file_name):
with open(file_name, 'rb') as f:
content = f.read()
client_socket.send(content)
else:
print('文件不存在!')
# 关闭socket
s.close()
import socket
# 创建socket
family = socket.AF_INET
type_ = socket.SOCK_STREAM
s = socket.socket(family, type_)
# 在发送数据之前,先与服务器进行连接
ip_address = '0.0.0.0'
port = 9099
address = (ip_address, port)
s.connect(address)
# 发送请求的文件名
file_name = input('Please input file name: ')
s.send(file_name.encode('utf8'))
# 接收文件
save_name = 'receive.' + file_name.split('.')[1]
with open(save_name, 'wb') as f:
while True:
content = s.recv(1024)
if not content:
break
f.write(content)
# 关闭socket
s.close()
多线程收发
import socket
import time
import threading
# 创建socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
my_port = 8099
address = ('0.0.0.0', my_port)
s.bind(address)
def send_msg(send_port=9099):
while True:
msg = input()
print('{}: {}'.format(my_port, msg))
s.sendto(msg.encode('utf8'), ('0.0.0.0', send_port))
time.sleep(1)
def recv_msg():
while True:
data, (_, port) = s.recvfrom(1024)
print('{}: {}'.format(port, data.decode('utf8')))
time.sleep(1)
thread1 = threading.Thread(target=send_msg)
thread2 = threading.Thread(target=recv_msg)
thread1.start()
thread2.start()
线程锁
线程锁能防止多个线程同时对一个全局变量进行操作
import threading
import time
ticket = 20
lock = threading.Lock()
def sell_ticket():
global ticket
while True:
lock.acquire()
if ticket > 0:
ticket -= 1
print('{}卖出一张票, 还剩{}张票'.format(threading.current_thread().name, ticket))
lock.release()
time.sleep(0.3)
else:
lock.release()
print('票卖完了')
break
t1 = threading.Thread(target=sell_ticket, name='线程1')
t2 = threading.Thread(target=sell_ticket, name='线程2')
t1.start()
t2.start()
服务器搭建
import socket
class MyServer(object):
def __init__(self, ip, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((ip, port))
self.socket.listen(128)
def run_forever(self):
while True:
client_socket, client_addr = self.socket.accept()
data = client_socket.recv(1024).decode('utf8')
print('接受到来自{}:{}的请求'.format(client_addr[0], client_addr[1]))
path = data.splitlines()[0].split(' ')[1]
print('请求的路径为{}'.format(path))
response_header = 'HTTP/1.1 200 OK\n'
if path == '/login':
response_body = '<h1 style="color:green">欢迎来到登录界面</h1>'
elif path == '/register':
response_body = '<h1 style="color:blue">欢迎来到注册界面</h1>'
elif path == '/':
response_body = '<h1 style="color:black">欢迎来到首页</h1>'
else:
response_header = 'HTTP/1.1 404 Page Not Found\n'
response_body = '<h1 style="color:red">您要查找的页面不存在!!!</h1>'
response_header += 'Content-Type: text/html;charset=utf-8\n' + '\n'
response = response_header + response_body
client_socket.send(response.encode('utf8'))
server = MyServer('0.0.0.0', 9090)
server.run_forever()
"""
---- Request Header ----
HTTP/1.1(响应采用的协议和版本号) 200(状态码) OK(描述信息)
Location: http://www.baidu.com(服务端需要客户端访问的页面路径)
Server:apache tomcat(服务端的Web服务端名)
Content-Encoding: gzip(服务端能够发送压缩编码类型)
Content-Length: 80(服务端发送的压缩数据的长度)
Content-Language: zh-cn(服务端发送的语言类型)
Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式)
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间)
Refresh: 1;url=http://www.it315.org(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径)
Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件)
Transfer-Encoding: chunked(分块传递数据到客户端)
Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据)
Expires: -1//3种(服务端禁止客户端缓存页面数据)
Cache-Control: no-cache(服务端禁止客户端缓存页面数据)
Pragma: no-cache(服务端禁止客户端缓存页面数据)
Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系)
Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间)
HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0xe8da5893001926cb
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Sun, 14 Jun 2020 16:03:45 GMT
Expires: Sun, 14 Jun 2020 16:03:44 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=522; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=1457_31670_21085_31069_32046_31714_30823_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1592150625018778983416778820750107289291
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
"""
"""
---- Response Header ----
GET(请求的方式) /newcoder/hello.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号)
Accept: */*(客户端能接收的资源类型)
Accept-Language: en-us(客户端接收的语言类型)
Connection: Keep-Alive(维护客户端和服务端的连接关系)
Host: localhost:8080(连接的目标主机和端口号)
Referer: http://localhost/links.asp(告诉服务器我来自于哪里)
User-Agent: Mozilla/4.0(客户端版本号的名字)
Accept-Encoding: gzip, deflate(客户端能接收的压缩数据的类型)
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(缓存时间)
Cookie(客户端暂存服务端的信息)
Date: Tue, 11 Jul 2000 18:23:51 GMT(客户端请求服务端的时间)
GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763
Accept-Encoding: gzip, deflate
Host: 192.168.1.14:9090
Connection: Keep-Alive
"""
WSGI服务器
from wsgiref.simple_server import make_server
def load_file(path, mode='r', encode=None):
try:
with open('html' + path, mode=mode, encoding=encode) as f:
file = f.read()
return file
except FileNotFoundError as e:
raise e
def show_login():
return '<h1 style="color:green">欢迎来到登录界面</h1>'
def show_register():
return '<h1 style="color:blue">欢迎来到注册界面</h1>'
def show_html(path):
if path.endswith('.jpg'):
return load_file(path, mode='rb')
else:
return load_file(path, encode='utf8')
url = {
'/login': show_login,
'/register': show_register,
}
def demo_app(environment, start_response):
"""
status code:
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
"""
"""
用来处理用户的请求
:param environment: 一个字典,存储用户环境
:param start_response: 是一个函数,用来返回response header
:return: 返回给浏览器的数据
"""
path = environment['PATH_INFO'] # 用户请求的路径
path = '/index.html' if path == '/' else path
status_code = '200 OK'
method = url.get(path)
if method:
response_body = method()
elif path.endswith('.jpg') or path.endswith('.html'):
response_body = show_html(path)
else:
status_code = '404 Page Not Found'
response_body = '<h1 style="color:red">您要查找的页面不存在!!!</h1>'
start_response(status_code, [('Content-Type', 'text/html;charset=utf-8')])
if not path.endswith('.jpg'):
response_body = response_body.encode('utf8')
return [response_body]
if __name__ == '__main__':
with make_server('0.0.0.0', 9090, demo_app) as http:
sa = http.socket.getsockname()
print('Serving HTTP on {}, port {} ...'.format(sa[0], sa[1]))
# 打开浏览器,输入访问地址
# import webbrowser
# webbrowser.open('http://localhost:9090/xyz?abc')
# http.handle_request() # 处理一次请求
http.serve_forever()