初识网络编程&并发编程

网络编程

交互方式

  基于同一台机器上的多个程序之间通信,可基于文件

  基于多台机器之间的通信,可基于网络

Web程序的两种构架

  C/S Client(客户端) Server(服务端)

  B/S Browser(浏览器) Server(服务端)

  浏览器本身也是客户端的一种

Mac地址

  唯一标识一台机器  12位16进制

协议

  IP协议: IP地址的规范

    IPv4协议 32位二进制4点分十进制

    IPv6协议 6冒分16进制组成

    交换机不识别IP地址,因此会一对所有广播,之后一对一单播

    交换机会完成:地址解析协议 arp协议

      通过IP地址找到一台机器的Mac地址

      交换机的广播与单播功能

    rap协议:通过IP地址找到Mac地址

局域网概念

  路由器:一个区域内的多台机器组成的一个网络

  域名:和IP地址有对应关系,我们访问的域名经过解析也能得到一个IP地址

网关IP概念

  IP地址另一个作用:区分区域网所在的IP范围

  在一台机器访问局域网外时使用的出口IP

IP地址

  比Mac简易,随机不固定,可按照区域划分

  IP地址+Mac地址确认机器

  127.0.0.1 本地的回环地址

  0.0.0.0 全网段地址

端口

  确认本机器上的具体应用

  帮助我们查找机器上的对应服务 

  范围:0-65535

  惯用端口:80,8000之后

子网掩码

  以相与来确认IP地址的所在范围

socket

  所有的网络通信的底层均是基于socket做的

  可使用socket模块来实现

import socket
sk
=socket.socket()#创建一个socket对象
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1# 表示允许端口复用
sk.bind(('127.0.0.1',10086))#绑定一个服务端地址,必须为元组(ip,端口) sk.listen()#开始接受客户端给我的连接 conn,addr=sk.accept()#阻塞 conn.send(b'welcome 10086')#给连我的人发消息 msg=conn.recv(1024)#阻塞:直到从连我的人那里就收消息 print(msg)#打印消息 conn.close()#关闭 挂电话 sk.close()#关闭 关机

而与之对应的

import socket
sk
=socket.socket() sk.connect(('127.0.0.1',10086)) msg=sk.recv(1024) print(msg) txt=input('>>>') sk.send(txt.encode('utf-8')) sk.close()

TCP协议

  面向连接 

    两台机器之间想要传递信息必须先建立连接

    之后在有了连接的基础上,进行信息的传递

  可靠  

    数据不会丢失或被重复接收

    传递信息后会等待一段时间,若未收到反馈则视为数据丢失,并再次发送

  慢

    TCP协议需要实现三次握手方可连接 (建立全双工的通信协议)

    传递信息后会等待一段时间,若未收到反馈则视为数据丢失,并再次发送

    且必须四次挥手断开连接

  常用于传递大型数据,例如文件,邮件,亦或是远程操控等

UDP协议

  无连接

    机器之间传递信息不需要建立连接 直接发送即可

  不可靠

    数据可能会丢失

  快

    只负责单向的数据传递

  UDP协议常用于即时通讯类软件 如QQ 微信 飞信 歪歪等

互联网协议与osi模型

  互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层

  osi

    应用层

      应用程序

    表示层

    会话层

    传输层

      端口 TCP/UDP协议 四层交换机 四层的路由器

    网络层

      IP地址相关 IP协议 路由器 三层交换机

    数据链路层

      mac地址相关 arp协议 网卡 二层交换机

    物理层

      中继器 集线器 双绞线

UDP

发送端

import socket

sk=socket.socket(type=socket.SOCK_DGRAM)   #type=socket.SOCK_DGRAM 设置使用UDP协议

sk.bind(('127.0.0.1',10087))  #地址及端口

conn,addr=sk.recvfrom(1024)  #recvfrom接受信息 与发送信息者传来的IP地址及端口号

sk.sendto(b'welcome',addr)  #sendto 发送信息 至指定的 IP地址的端口
print(conn.decode('utf8'))

sk.close()

接收返回端

import socket

sk=socket.socket(type=socket.SOCK_DGRAM)
conn=('127.0.0.1',10087)  #这里写入 自己IP地址 及 端口号

sk.sendto(b'xxx',conn)  #sendto发送信息 及 自身IP地址得端口号
msg,_=sk.recvfrom(1024)  #recvfrom 接收信息
print(msg.decode('utf8'))

sk.close()

粘包

粘包解决方式

本次行动接收者server服务端

import socket
import struct

sk=socket.socket()
sk.bind(('127.0.0.1',10089))
sk.listen()

conn,addr=sk.accept()
num=conn.recv(4)
num=struct.unpack('i',num)[0]
msg=conn.recv(num)
print(msg.decode('utf-8'))

sk.close()

 本次行动发送者client客户端

import socket
import struct

server=socket.socket()
server.bind(('127.0.0.1',10086))
server.listen()

conn,addr=server.accept()

ret=conn.recv(4)
long=struct.unpack('i',ret)[0]
print(long)
msg=conn.recv(long)
print(msg.decode('utf8'))
conn.recv(1024)

第二种socket套接字创建方式

socketserver 模块

socket模块是socketserver模块的底层模块,socketserver模块是基于socket模块创建的

自带并行  指多个任务于多个cpu上同时进行

import socketserver     #导入socketserver模块
import os
import hmac     #关于加密算法的内置模块/使用的是md5加密算法

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):   #socketserver模块中固定的方法名,由父类的__init__方法调用
        key_client = 'my server'  #
        conn=self.request   #获取自己IP地址 及 端口号
        txt=os.urandom(32)  #随机生成一个字节串
        conn.send(txt)
        txt=hmac.new(key=key_client.encode(),msg=txt).hexdigest().encode('utf-8')
        # key,msg均为字节,不可加入字符串等,输出为内存地址,hexdigest()转为字符串
        msg=conn.recv(1024)
        if txt==msg:
            print('合法')
        else:
            conn.close()
            print('已执行')


obj=socketserver.ThreadingTCPServer(('127.0.0.1',10086),Myserver)
# 实例化 ((地址及端口),类名)  ps:类名是可更改的,仅handle方法名固定
obj.serve_forever()
# 调用socketserver模块中的serve_forever()方法

进程

特别注意子进程任务中若使用 input 函数会报 EOF 的错

进程的创建

  开机启动的程序

  在运行中再开启一个进程


进程的结束

  正常退出

  出错退出(资源)

  严重出错(非自愿)

  被其他进程杀死

多级反馈队列

多个阶层 1→∞ 优先级降序


sys.argv

   生成一个索引0为此py文件绝对路径的列表


使用模块操作进程


import multiprocessing   导入一个多元化的进程模块
multiple  多元化           processing   进程


Process  进程类

正常实现一个调用多次函数的代码

import os
import time
def func(i):
    time.sleep(1)
    print(i, os.getpid())
print('主:',os.getpid())
func(0)
func(1)
func(2)

结果会被按顺序,一个一个的打印出来

这样很稳定,但也很浪费时间

如果我们尝试着加入进程
from multiprocessing import Process  导入multiprocessing模块中的Process方法

from multiprocessing import Process

# multiprocessing是个包
# Process进程类
def func(a,b,c):
    time.sleep(1)
    print(a,b,c, os.getpid())
if __name__=='__main__':
    # p=Process(target=func)
    # p.start()
    print('主:',os.getpid())
    p=Process(target=func,args=(1,2,3))
    p.start() #开启一个进程 异步非阻塞模型 高效率
    print(p.is_alive()) #判断进程是否存活
    print(p.name) #进程名字
    print(p.pid) #pid
    # Process(target=func,args={1:2,2:3,3:4}).start()
    # Process(target=func,args=[1,2,5]).start()
    p.terminate() #结束一个进程 异步非阻塞模型 高效率
    print(p.is_alive())
    time.sleep(0.1)
    print(p.is_alive())
# 进程之间数据隔离 子进程中返回的值父进程获取不到
# 上例为异步 start()为开启进程 target=为指定目标函数
# multiprocessing是个包

join可以实现进程的阻塞

import random
def send_mail(name):
    time.sleep(random.uniform(1,3))
    print('已经给%s发送邮件完毕'%name)
if __name__=='__main__':
    lst=['alex','yuan']
    p_l=[]
    for name in lst:
        # 阻塞等待一个子进程进程结束
        p=Process(target=send_mail,args=[name,])
        p.start() #异步非阻塞
        p_l.append(p)
        # p.join() #阻塞 直到p对应的进程结束之后才结束阻塞
    print(p_l)
    i=0
    for p in p_l:
        i+=1
        print(i)
        p.join()
        print(i)
    print('所有信息发送完毕')

def func():
    for i in range(20):
        time.sleep(0.5)
        print('in func')
if __name__=='__main__':
    p=Process(target=func)
    p.daemon=True #设置守护进程
    p.start()
    print('in main')
    time.sleep(3)
    print('finished')

主进程与子进程互不干扰
 主进程执行完毕之后程序不会结束,会等待所有的子进程结束之后才结束
为什么主进程要等待子进程结束之后才结束
    因为主进程要负责给子进程回收一些系统资源
守护进程:
    是一个子进程,守护的是主进程
    结束条件:主进程的代码结束,守护进程结束
        守护进程也是个子进程,需要被主进程回收资源

进程
    主进程的代码结束,守护进程结束
    主进程要回收守护进程(子进程)的资源
    主进程等待其他所有子进程结束
    主进程回收所以子进程的资源

原文地址:https://www.cnblogs.com/lttlpp61007188/p/10671084.html