网络编程自我感觉还是很重要的一部分

网络基础

C/S架构 client/server
B/S架构 server/browser
 两者的关系?
 B/S架构是C/S架构的一种

计算机与计算机之间是如何通信的?

两台计算机之间的通信

网卡、网线

网卡:提供网线的接口,通过网卡找到计算机,一个网卡拥有全球唯一的mac地址

同一个局域网中多台计算机之间的通信

网卡,网线,交换机

交换机:一个中心节点,所有的网线连接到交换机上

计算机1寻找计算机2并发消息的过程:

  计算机1发送消息到交换机,交换机把这个信息广播给局域网中所有计算机,计算机2收到消息与自己的mac地址比对,确认是发给自己的消息之后,回复消息给交换机,交换机发消息到计算机1

不同局域网中多台计算机之间的通信

网卡,网线,交换机,路由器

路由器:连接多个交换机

广播:计算机1要和计算机2通信,告诉交换机要找计算机2,交换机会告诉所有的计算机要找计算机2
广播风暴:所有的计算机同时去找,同一台计算机会接收到很多与自己不相关的信息,从而造成网络拥堵
单播:只有计算机2会回复消息给交换机,交换机发送给计算机1

网关:不同的局域网中的计算机之间通信,同一个局域网的默认网关相同
子网掩码:ip地址和子网掩码按位与 (计算出来局域网的网段,同一个网段只有最后一位不同,前三位都相同)来判断是否在同一局域网
按位与:1|1=1,1|0=1,0|0=0

ip地址

4个点分十进制(4个八位二进制数)范围:0-255

作用:
通过ip地址可以找到对应的mac地址 根据arp协议
127.0.0.1:本地回环地址,本地中的两个程序通信

ip协议

IPV4:0.0.0.0-255.255.255.255
IPV6:0.0.0.0.0.0-255.255.255.255.255.255
作用:1.为一台计算机分配ip地址
   2.计算计算机的网段
如果想让别人能访问到自己的计算机中的程序,必须有一个已经在公网中注册的ip地址

端口

计算机里边的每一个需要联网的程序都有一个端口

qq聊天时,对方不仅需要你的ip地址,还需要qq程序的端口号
端口的范围:0-25535
自己开端口:开8000后的端口

互联网协议

每层的工作

  应用层   程序,要发送的数据包
  传输层   选择通信协议,给要发送的数据加上协议
  网络层   给要发送的数据加上ip信息
  数据链路层    通过arp协议得到mac地址,给要发送的数据加上mac地址
  物理层   两个计算机链接
每层用到的协议:

  应用层   http协议,SMTP协议,ftp协议
  传输层   TCP/UDP协议
  网络层   ip协议
  数据链路层   ARP协议
  物理层
每层常见物理设备:

  应用层
  传输层   四层交换机,四层路由器
  网络层   路由器,三层交换机(带路由功能)
  数据链路层    网桥,交换机,网卡
  物理层   中继器,双绞线,集线器

TCP协议/UDP协议

TCP协议:可靠的,建立链接的
  全双工通信:双方可以互相收发信息
  三次握手:一定是client先请求发送--server端接受请求并且请求发送--client端接收请求 通道连接成功
  四次挥手:client/server请求断开连接--server/client同意断开--server/client请求断开连接--client/server同意断开
UDP协议:
  不建立链接的,不可靠的

网络编程

使用socket编程来进行进程间的通讯

基于TCP协议的socket编程

TCP服务端:创建套接字 (socket)--绑定端口 (bind)--倾听客户请求(listen)--接受客户端连接(accept)--接受、发送(recv、send)--关闭套接字(closesocket)
TCP客户端:创建套接字(socket)--链接服务器(connect)--发送,接受(send、recv)--关闭套接字(closesocket)

import socket
soc = socket.socket()  #手机开机
soc.bind(('localhost',9999))    #启动SIM卡
soc.listen()    #等待别人打电话
connect,addr = soc.accept()     #拿到通话连接,别人的电话号
recv = connect.recv(1024)       #听别人讲话
send = connect.send(b'hello')       #对别人讲话
print(str(recv))
connect.close()     #挂断电话
soc.close()     #关机
TCP_Server
import socket
sock = socket.socket()      #手机开机
sock.connect(('localhost',9999))       #给别人打电话
sock.send(b'jcc')       #对别人讲话
rec = sock.recv(1024)       #听别人讲话
print(str(rec))
sock.close()    #关机
TCP_Client

基于UDP协议的socket编程

import socket
udpsk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字  DGRAM:datagram  基于udp传输的数据包
udpsk.bind(('localhost',8888))      #绑定指定服务器
while 1:
    msg,addr = udpsk.recvfrom(1024)     #接受消息
    print(msg.decode('utf-8'))
    if msg.decode('utf-8')=='bye':break
    inp = input('>>>')
    udpsk.sendto(bytes(inp,encoding='utf-8'),addr)  #发送消息
udpsk.close()  #关闭套接字
UDP_Server
import socket
udpsk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字  DGRAM:datagram  基于udp传输的数据包
udpsk.bind(('localhost',8888))      #绑定指定服务器
while 1:
    msg,addr = udpsk.recvfrom(1024)     #接受消息
    print(msg.decode('utf-8'))
    if msg.decode('utf-8')=='bye':break
    inp = input('>>>')
    udpsk.sendto(bytes(inp,encoding='utf-8'),addr)  #发送消息
udpsk.close()  #关闭套接字
UDP_Client

数据传输过程中的黏包现象

现象:
    接受和发送不匹配
    
    基于UDP协议的传输不会出现黏包现象,一次接收不完的信息会被丢掉
    基于TCP协议的传输会出现黏包现象,但是不丢包
    基于UDP协议的传输会限制数据包的大小,超过的信息被丢掉
    基于TCP协议的传输不会限制数据包的大小
产生黏包的原因:
    TCP协议是面向流的,无边界的
    TCP协议有一种拆包机制,当发送的数据包大于网关的mtu(网络上传输的最大数据包),该数据包就会被拆开,分批发送
 
     Nagle算法:优化传输速度(将多次间隔较小且数据量小的数据合并成一个大的数据块,封包)导致黏包现象
    
    黏包出现的最终原因:不知道要接受的数据有多大

解决黏包方式1

先发送数据包的长度,根据长度接受数据(缺点:多了一次客户服务器之间的交互)

import socket
sock = socket.socket()
sock.bind(('127.0.0.1',9991))
sock.listen()
conn,addr = sock.accept()
while 1:
    cmd = input('>>>')
    conn.send(cmd.encode('gbk'))

    len1 = conn.recv(1024)  #先接受长度

    recv = conn.recv(int(len1.decode('gbk')))   #根据长度接受数据包
    print('std:'+recv.decode('gbk'))
解决黏包Server
import socket
import subprocess
sock = socket.socket()
sock.connect(('127.0.0.1',9991))
while 1:
    cmd = sock.recv(1024)
    #执行计算机命令subprocess
    sb = subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    stdout = sb.stdout.read()
    stderr = sb.stderr.read()
    print('stdout'+str(len(stdout)))
    print('stderr' + str(len(stderr)))

    sock.send(str(len(stdout)+len(stderr)).encode('gbk'))   #发送长度

    sock.send(stdout)   #发送消息
    sock.send(stderr)
解决黏包Client

借助struct模块解决黏包

struct模块

import struct
p = struct.pack('i',20)#int转bytes
print(p)
num = b'1223'
unp = struct.unpack('i',num)[0]#bytes转int
print(unp)
struct介绍

socketServer

import socketserver
class Myserver(socketserver.BaseRequestHandler):    #继承BaseRequestHandler
    def handle(self):               #重写handle函数
        self.data = self.request.recv(1024)     #self.request相当与conn,接受信息
        print(self.client_address[0])
        print(self.data.decode('utf-8'))
        self.request.sendall(self.data) #发送消息

if __name__ == '__main__':
    host,port = '127.0.0.1',9999
    socketserver.TCPServer.allow_reuse_address = True   # 设置allow_reuse_address允许服务器重用地址
    server = socketserver.TCPServer((host,port),Myserver)     # 创建一个server, 将服务地址绑定到127.0.0.1:9999
    server.serve_forever()  #程序一直运行
socketserver

 

posted on 2018-09-18 16:31  蒋丞丞  阅读(148)  评论(0编辑  收藏  举报