网络协议三要素: 语法,语义,时序
常见应用层协议: ftp,http,smtp,pop3,tlnet…
传输层协议**: tcp,udp,端口号**
ip地址: ipv4 , ipv6
MAC地址:网卡地址(唯一的)
socket = ip : 端口号
udp适用于对效率要求较高而对准确性要求相对较低的场合,例如视频在线点播,网络语音通话
tcp 适用于对传输效率低 ,对准确性高的场合,列如文件传输,
需要建立连接,数据传输,断开连接三个步骤
1.创建服务器端套接字Socket,监听客户端的连接请求。
(1)通过socket()函数创建服务器端套接字Socket对象;
(2)Socket对象用bind()函数把服务器的IP地址绑定到这个套接字上;
(3)Socket对象用listen()函数监听客户端的连接请求;
(4)Socket对象用accept()函数等待并接收客户端的连接,连接成功则创建一个新的通信套接字。
2 创建客户端Socket对象,向服务器端发起连接
(1)通过socket()函数创建客户端Socket对象;
(2)客户端Socket对象用connect()函数发起连接请求。
(3)建立连接。
3. 客户机与服务器通信
(1)服务器通信套接对象用sendall()函数向客户端发送信息;
(2)客户端套接字Socket对象用recv()函数接收服务器发来的信息;
(3)客户端套接字Socket对象用sendall()函数向服务器发送信息;
(4)服务器通信套接字对象用recv()函数接收客户端发来的信息;
(5)通信完毕,使用close()函数关闭套接字。
例子
server 代码
from socket import *
HOST = '127.0.0.1'
PORT = 4321
ADDR = (HOST,PORT)
# socket()函数创建服务器端套接字Socket对象;
ss=socket(AF_INET,SOCK_STREAM,0)
# 用bind()函数把服务器的IP地址绑定到这个套接字上
ss.bind(ADDR)
# 用listen()函数监听客户端的连接请求;
ss.listen(10)
print('等待客户机连接......\n')
# accept()函数等待并接收客户端的连接,连接成功则创建一个新的通信套接字。
cs, caddr = ss.accept()
print('连接的客户机来自于', caddr)
str = '欢迎访问本服务器'
# 将数据返回给客户端
cs.sendall(bytes(str, 'UTF-8'))
while True:
msg = cs.recv(1024).decode()
print('接受客户机信息:', msg)
send_msg = input("请输入返回给客户端的信息(quit跳过本次链接):")
if send_msg == "quit":
cs.sendall(bytes(" ", 'UTF-8'))
else:
cs.sendall(bytes(send_msg, 'UTF-8'))
ss.close()
client代码
from socket import *
HOST = '127.0.0.1'
PORT = 4321
ADDR = (HOST, PORT)
# 创建socket对象
cs = socket(AF_INET, SOCK_STREAM, 0)
# 获取服务器连接的信息 (是否成功)
cs.connect(ADDR)
data = cs.recv(1024).decode()
print("服务器返回的信息:",data)
while True:
send_data = input("请输入要发送的数据:")
# 发送的数据为空就返回
if not send_data or send_data == 'quit':
break
cs.sendto(send_data.encode('utf-8'),ADDR)
# 如果没有收到数据则会阻塞等待 直到收到数据
msg = cs.recv(1024).decode()
if msg==" ":
print("服务器没有搭理你")
continue
# 1024表示本次接收的最大字节数
print("服务器消息:",msg)
cs.close()
服务器自动回复tcp写法
server端
import random
import socket
from os.path import commonprefix
# 主机地址
HOST = '127.0.0.1'
# 开设端口
PORT = 8005
# 词库
words = {
'hello': 'hello',
'你好': '你好',
'how are you?': 'Fine, thank you',
'how old are you?': '20岁',
'bye': 'bye',
'python': ["考虑一千次,不如去做一次;犹豫一万次,不如实践一次;华丽的跌倒,胜过无谓的彷徨,将来的你,一定会感谢现在奋斗的你。",
"没有所谓失败,除非你不再尝试。无论你昨晚经历了怎样的泣不成声,早上醒来这个城市依旧车水马龙。宁可笑着流泪,绝不哭着后悔。",
"一朵花凋零荒芜不了整个春天,一次跌倒也荒废不了整段旅程。走下去,凭着耐心和拼搏,生活自会给予你全部答案",
"行动,是打败焦虑的最好办法。当你不知道该做什么的时候,就把手头的每件小事都做好;当你不知道该怎么开始时,就把离你最近的那件事情做好!",
"每天给自己一个希望,试着不为明天而烦恼,不为昨天而叹息,只为今天更美好!人生没有对错,只有选择后的坚持,不后悔,走下去,就是对的。走着走着,花就开了。",
"宁愿跑起来被拌倒无数次,也不要规规矩矩走一辈子。就算跌倒也要豪迈的笑。",
"不去追逐,永远不会拥有。不往前走,永远原地停留。知道自己目的地的人,才是旅行得最远的人。",
"再长的路,一步步也能走完,再短的路,不迈开双脚也无法到达。行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。",
"对别人说狠话,不如对自己下狠手;扛得住艰难,才能配得上梦想;不想苦一辈子,就要苦一阵子!",
"心在哪里,收获就在哪里。人这一生能力有限,但是努力无限。努力做一个善良的人,做一个心态阳光的人,做一个积极向上的人,用正能量激发自己,也感染身边的人。用最美的心情迎接每天的朝阳!你阳光,世界也会因你而光彩。",
"如果真的不知道将来要做什么,索性就先做好眼前的事情。只要今天比昨天过得好,就是进步。长此以往,时间自然会还你一个意想不到的未来。",
"生活不会按你想要的方式进行,它会给你一段时间,让你孤独、迷茫又沉默忧郁。等你度过低潮,那些独处的时光必定能照亮你的路,也是这些不堪陪你成熟。",
"别人拥有的,你不必羡慕,只要努力,你也会拥有;自己拥有的,你不必炫耀,因为别人也在奋斗,也会拥有。",
"你要明白很多时候,抱怨是没有用的,抱怨一天远没有努力一会的收获大。所以,努力吧!将所有的抱怨与不满都化作动力,强大给这个世界看!",
"不到最后一刻,千万别放弃。最后得到好东西,不是幸运,有时候,必须有前面的苦心经营,才有后面的偶然相遇。"]
}
# AF_INET = ipv4 , SOCK_STREAM = tcp链接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
# 监听一个客户端连接
s.listen(1)
print('监听端口:', PORT)
conn, addr = s.accept()
print('客户机已接入:', addr)
# 开始聊天
while True:
data = conn.recv(1024).decode()
if not data:
break
print('接收消息:', data)
# 尽量猜测对方要表达的真正意思
m = 0
key = ""
for k in words.keys():
# 删除多余的空白字符串
data = ' '.join(data.split())
# 与某个键接近就直接返回 从第一个字符开始比较返回两个字符之间最长的字符
if len(commonprefix([k, data])) > len(k) * 0.7:
key = k
break
# 当第一个字符与之不匹配时或者小于70%这个度时 进入第二轮比较
# set交集越长 说明匹配度越高
length = len(set(data.split()) & set(k.split()))
if length > m:
m = length
key = k
# 鸡汤语录
if key == 'python':
index = random.randint(1, 15)
conn.sendall(('心灵鸡汤:' + words.get('python')[index]).encode())
else:
conn.sendall(words.get(key, 'sorry').encode())
conn.close()
s.close()
client端
import socket
import sys
# 服务端主机ip地址和端口号
HOST = '127.0.0.1'
PORT = 8005
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 连接服务器
s.connect((HOST, PORT))
except Exception as e:
print('服务器还没开启.....')
sys.exit()
while True:
c = input('请输入发送的内容:')
s.sendall(c.encode())
# 从服务端接收数据
data = s.recv(1024)
data = data.decode()
print('收到消息:', data)
if c.lower() == 'bye':
break
# 关闭连接
s.close()
server
import socket
from datetime import datetime
# 使用ipv4, UDP协议传数据
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 5005))
while True:
data, addr = s.recvfrom(1024)
# 显示接收到消息
print('received message:{0} from {1}'.format(data.decode(), addr))
if data == b'ask for time':
now = str(datetime.now())[:19]
s.sendto(now.encode(), addr)
s.close()
client
import socket
import time
while True:
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto(b'ask for time',('0.0.0.0',5005))
data,addr = s.recvfrom(1024)
print(data.decode())
s.close()
time.sleep(2)
==================================================================
服务器自动回复udp写法
server端写法
import socket
from os.path import commonprefix
HOST = '127.0.0.1'
PORT = 8085
words = {
'how are you?': 'Fine, thank you',
'how old are you?': '20',
'bye': 'bye'
}
# AF_INET = ipv4 , SOCK_DGRAM = UDP链接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((HOST, PORT))
# 开始聊天
while True:
data,addr = s.recvfrom(1024)
data = data.decode()
if not data:
break
print(addr,':', data)
# 尽量猜测对方要表达的真正意思
m = 0
key = ""
for k in words.keys():
# 删除多余的空白字符串
data = ' '.join(data.split())
# 与某个键接近就直接返回
if len(commonprefix([k, data])) > len(k) * 0.7:
key = k
break
length = len(set(data.split()) & set(k.split()))
if length > m:
m = length
key = k
s.sendto(words.get(key, 'sorry').encode(),addr)
s.close()
client端写法
import socket
# 服务端主机ip地址和端口号
HOST = '127.0.0.1'
PORT = 8085
# AF_INET = ipv4 , SOCK_DGRAM = UDP链接
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
c = input('Input the content you want to send:')
s.sendto(c.encode(),(HOST,PORT))
# 从服务端接收数据
data = s.recv(1024)
data = data.decode()
print('Received:',data)
if c.lower() == 'bye':
break
# 关闭连接
s.close()
==================================================================
用多线程编写 server端
import socket
import threading
PORT = 8006
HOST = ''
def server(conn , addr):
# threading.active_count() - 1是因为主线陈也在运行
print('总共连接数数量:',threading.active_count()-1)
print('连接的客户机来自于:',addr)
conn.sendall('欢迎访问本服务器'.encode())
conn.close()
if __name__ == '__main__':
# 链接ipv4 , 传输tcp协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip和地址
s.bind((HOST, PORT))
# 允许连接数为5个
s.listen(5)
while True:
print('等待客户机连接.......')
conn ,addr = s.accept()
t =threading.Thread(target=server,args=(conn , addr,))
t.start()
client端
from socket import *
HOST = '0.0.0.0'
PORT = 8006
ADDR = (HOST, PORT)
# 创建socket对象
s = socket(AF_INET, SOCK_STREAM)
# 获取服务器连接的信息 (是否成功)
s.connect(ADDR)
data = s.recv(1024).decode()
print("服务器返回的信息:",data)
s.close()