@[toc]
网络结构
- ISP
- Internet Service Provider
- 一个或多个分组交换机在多段通信链路组成的网络
- 提供不同类型的网络接入
- 独立运营
- ISP分层
- 第一层:因特网主干
Sprint,AT&T,Level3 - 第二层:具有区域性或国家性覆盖规模,引导流量通过,也可以跟其他第二层ISP交换流量
Provider-custoner
Peer-peer - 较低层:通过一个或多个第二层ISP与更大的因特网连接
- 第一层:因特网主干
网络结构
- 接入点POP
ISP与ISP的连接点,由一个或多个路由器组成 - 网络接入点NAP
由第三方通信公司或因特网主干提供 -
接入方式
- Socket
应用层与TCP/IP协议族通信的中间软件抽象层 - TCP socket编程
函数 | 作用 |
---|---|
AF_INET | 使用IPv4协议 |
AF_INET6 | 使用IPv6协议 |
SOCK_STREAM | 指定使用面向流的TCP协议 |
bind() | 绑定端口,端口号不小于1024 |
listen() | 监听窗口,并指定等待连接的最大数量 |
accept() | 等待并返回一个客户端连接 |
connect() | 主动连接服务端 |
recv() | 接收TCP数据 |
send() | 发送TCP数据 |
tcpserver.py
文件,服务器端启动,监听用户端发起的连接
tcpclient.py
文件,用户端启动,发起对服务器的连接
连接之后相互之间可以通话,但同一时间只能保证一条连接
当还有其他用户连接时只能等待,当前一个用户断开连接之后,下一个用户才能继续连接。
#tcpserver.py
import sys
import os
from socket import *
import time
import random
HOST='127.0.0.1'
RSIZE=1024
class TCPServer:#非多线程,只能响应一个client
def __init__(self,port,maxconnections=5):
self._port=port
self._maxconnections=maxconnections
self._server=socket(AF_INET, SOCK_STREAM)
def start(self):
self._server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
self._server.bind((HOST,self._port))
self._server.listen(self._maxconnections)
print("SERVER is listening on %s" % self._port)
while True:#如果有多个client同是发起连接,只响应一个,其他会等待
conn,addr=self._server.accept()#block
print(f"client's connection: {conn}, its address:{addr}")
while True:
try:
data=conn.recv(RSIZE)
if not data:
break
print("CLIENT: %s" % data.decode('utf-8'))
if data.decode('utf-8')=='bye':
conn.send("再见!".encode('utf-8'))
break
else:
conn.send('收到!'.encode('utf-8'))
except Exception as e:
print("SERVER ERROR: %s" % e)
break
conn.close()
self._server.close()
def main():
ser=TCPServer(int(sys.argv[1]))
#ser = TCPServer(2021)
ser.start()
if __name__=='__main__':
main()
#tcpclient.py
import os
import sys
import time
import random
from socket import *
from tcpserver import TCPServer
class TCPClient:
def __init__(self,server_ip,server_port):
self._server_ip=server_ip
self._server_port=server_port
self._client=socket(AF_INET,SOCK_STREAM)
def start(self):
self._client.connect((self._server_ip,self._server_port))
while True:
msg=input("CLIENT:")
self._client.send(msg.encode('utf-8'))
data=self._client.recv(1024)
if not data:
continue
if(data.decode('utf-8')=='再见'):
print("结束连接")
break
else:
print("SERVER: %s" % data.decode('utf-8'))
self._client.close()
def main():
client=TCPClient(sys.argv[1],int(sys.argv[2]))
#client = TCPClient('127.0.0.1',2021)
client.start()
if __name__=='__main__':
main()
使用多线程模拟多人聊天
#mtserver.py
import sys
import os
from threading import Thread
from socket import *
BUFFERS=1024
MAXC=64
def speak(name,conn):
print("欢迎{}进入聊天室...".format(name))
while True:
try:
msg=conn.recv(BUFFERS)
if not msg:
break
print("{}:{}".format(name,msg.decode('utf-8')))
if msg.decode('utf-8')=='byebye':
print("{}离开了聊天室...".format(name))
break
except Exception as e:
print("server error %s" % e)
break
conn.close()
if __name__=='__main__':
ip=sys.argv[1]
port=int(sys.argv[2])
server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
server.bind((ip,port))
server.listen(MAXC)
print("MT server is started...")
while True:
conn,addr=server.accept()#block
ci,cp=addr
#启动一个线程处理该连接,主线程继续处理其他连接
t=Thread(target=speak,args=("client-"+ci+"-"+str(cp),conn))
t.start()
server.close()
#mtclient.py
import sys
from socket import *
from threading import Thread
import random
import time
CHARS='abcdefghijklmnopqrstuvwxyz'
ROUND=8
class ChatBot(Thread):
def __init__(self,ip,port,mlength):
super().__init__()
self._ip=ip
self._port=port
self._max_msg_length=mlength
def _random_message(self):
message=[]
for i in range(self._max_msg_length):
word=[]
for j in range(random.randint(1,5)):
word.append(random.choice(CHARS))
message.append(''.join(word))
return ' '.join(message)
def run(self):
_client=socket(AF_INET,SOCK_STREAM)
_client.connect((self._ip,self._port))
_sent_count=0
while True:
msg=self._random_message()
_client.send(msg.encode('utf-8'))
_sent_count+=1
time.sleep(random.randint(1,5))
if _sent_count>ROUND:
_client.send('byebye'.encode('utf-8'))
break
_client.close()
def main():
ip=sys.argv[1]
port=int(sys.argv[2])
tlist=[]
for i in range(int(sys.argv[3])):
tlist.append(ChatBot(ip,port,random.randint(4,8)))
for t in tlist:
t.start()
for t in tlist:
t.join()
print("All bots exit...")
if __name__=='__main__':
main()
在同一个程序里面同时实现server和client的功能,需要多加一个参数指定是server还是client。
#schat.py
from socket import *
from threading import Thread
import sys
BS=2048
def recv(name,conn):
while True:
data=conn.recv(BS)
if not data:
break
if data.decode('utf-8')=='BYEBYE':
print("对方提议停止聊天,输入BYEBYE可终止...")
break
else:
print("%s: %s" % (name,data.decode('utf-8')))
def send(conn):
while True:
msg=input("")
if not msg:
continue
conn.send(msg.encode('utf-8'))
if msg=='BYEBYE':
break
if __name__=='__main__':
if len(sys.argv)!=4:
print('usage: python schat.py ip port server|client')
else:
ip=sys.argv[1]
port=int(sys.argv[2])
name=sys.argv[3]#server, client
server=socket(AF_INET,SOCK_STREAM)
if name=='server':
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind((ip,port))
server.listen(5)
print("server started...")
conn,addr=server.accept()
if name=='client':
server.connect((ip,port))
print('client connected...')
addr=(ip,port)
conn=server
tr=Thread(target=recv,args=(str(addr),conn))
tr.start()
ts=Thread(target=send,args=(conn,))
ts.start()
tr.join()
ts.join()
conn.close()
server.close()
HTTP
http.server
– Defines classes for implementing HTTP servers (Web
servers)
• HttpServer/ThreadingHttpServer
: creates and listens at the HTTP socket, dispatching the requests to a handler
• Handler: BaseHTTPRequestHandler,
SimpleHTTPRequestHandler
http.client
– Defines classes which implement the client side of the HTTP and HTTPS protocols
– It is normally not used directly
– urllib.request
uses it to handle URLs that use HTTP and HTTPS
UDP的优势
- 应用层能更好地控制要发送的数据和发送时间
- 无需连接建立
- 不需要任何准备即可进行数据传输
- 不引入建立连接的时延
- 无连接状态
- 无需维护一些状态参数
- 分组头部开销小,TCP头至少占20字节,UDP头占8个字节
#udpserver.py
import sys
import os
from socket import *
import time
import random
HOST='127.0.0.1'
RSIZE=1024
class TCPServer:#非多线程,只能响应一个client
def __init__(self,port,maxconnections=5):
self._port=port
self._maxconnections=maxconnections
self._server=socket(AF_INET, SOCK_STREAM)
def start(self):
self._server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
self._server.bind((HOST,self._port))
self._server.listen(self._maxconnections)
print("SERVER is listening on %s" % self._port)
while True:#如果有多个client同是发起连接,只响应一个,其他会等待
conn,addr=self._server.accept()#block
print(f"client's connection: {conn}, its address:{addr}")
while True:
try:
data=conn.recv(RSIZE)
if not data:
break
print("CLIENT: %s" % data.decode('utf-8'))
if data.decode('utf-8')=='bye':
conn.send("再见!".encode('utf-8'))
break
else:
conn.send('收到!'.encode('utf-8'))
except Exception as e:
print("SERVER ERROR: %s" % e)
break
conn.close()
self._server.close()
def main():
ser=TCPServer(int(sys.argv[1]))
#ser = TCPServer(2021)
ser.start()
if __name__=='__main__':
main()
#udpclient.py
import os
import sys
import time
import random
from socket import *
from tcpserver import TCPServer
class TCPClient:
def __init__(self,server_ip,server_port):
self._server_ip=server_ip
self._server_port=server_port
self._client=socket(AF_INET,SOCK_STREAM)
def start(self):
self._client.connect((self._server_ip,self._server_port))
while True:
msg=input("CLIENT:")
self._client.send(msg.encode('utf-8'))
data=self._client.recv(1024)
if not data:
continue
if(data.decode('utf-8')=='再见'):
print("结束连接")
break
else:
print("SERVER: %s" % data.decode('utf-8'))
self._client.close()
def main():
client=TCPClient(sys.argv[1],int(sys.argv[2]))
#client = TCPClient('127.0.0.1',2021)
client.start()
if __name__=='__main__':
main()
SMTP
- Simple Mail Transfer Protocol
- 从发送方的邮件服务器向接收方的邮件服务器发送邮件
- 运行在发送方邮件服务器的客户机端和接收方邮件服务器的服务器端
- MIME:多用途互联网邮件扩展
POP3
- 与服务器建立连接(默认是110端口)
- 认证——事务处理——更新
- 未给用户提供任何创建远程文件夹以及为报文指派文件夹的方法
IMAP
- 互联网邮件访问协议
- 创建文件夹并在文件夹之间移动邮件
- 允许只读取报文头部
网友评论