Python全栈开发之网络编程

No.1 TCP/IP

早期的计算机网络,都是由厂商规定自己的通信协议,互不兼容,为了把全世界不同类型的计算机连接起来,就必须规定一套全球通用的协议,所以就出现了TCP/IP

No.2 Socket简介

要解决怎么标识一个进制,在一台电脑上可以同pid标识进程,但是在网络上是做不到的,其实TCP/IP就帮我们解决了这个问题,网络层的IP可以标识在网络上的主机,而传输层的协议+端口就可以标识主机中

什么是Socket

socket是进程通信的的一种方式,它与其他进程通信的不同是,它能实现不同主机之间的进程通信,我们网络的应用大多数都是采用这种方式进行通信的

创建Socket

在Python中使用socket模块

import socket
socket.socket(AddressFamily, Type)

函数socket可以创建一个socket对象,该函数存在两个参数

Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET

Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

创建一个tcp套接字

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.close()

创建一个udp套接字

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.close()

Socket函数

bind(address) 将套接字绑定到地址,在AF_INET下,以元祖(hsot,port)的形式表示地址
listen(backlog) 开始监听TCP传入连接,backlog指定可以挂起的最大连接数
accept() 接收TCP连接并返回(conn,address),其中conn是新的套接字对象,address是连接客户端的地址
connect(address) 连接到address处的套接字,以元祖(hsot,port)的形式表示地址,连接出错返回socket.error错误
connect_ex(address) 功能与s.connect(address) ,但是成功返回0,失败返回errno的值
recv(bufsize[,flag]) 接收TCP套接字的数据,数据以字节形式返回,bufsize指定接收的最大数据量,flag提供有关消息的其他信息,通常可以忽略
send(string[,flag]) 发送TCP数据,将string中的数据发送到连接的套接字,返回值是要发送的字节数量
sendall(string[],flag) 完整的发送TCP数据,返回之前会尝试发送所有数据,成功返回Nonne,失败抛出异常
recvfrom(bufsize[,flag]) 接收UDP套接字的数据,与s.recv()类似,但返回值是(data,address),data表示接收的数据,address表示发送数据的套接字地址
sendto(string[,flag],address) 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,返回值是发送的字节数
close() 关闭套接字
getpeername() 返回连接套接字的远程地址,返回值是形式为(ipaddr,port)的元组
getsockname() 返回u套接字自己的地址,返回值是形式为(ipaddr,port)的元组
setsockopt(level,optname,value) 设置给定套接字选项的值
setsockopt(level,optname[.buflen]) 返回套接字选项的值
settimeout(timeout) 设置套接字及操作的朝时期,tiemout为一个浮点数,单位是秒,值为None表示永远没有朝时期
setblocking(flag) 如果flag为0,则将套接字设为非阻塞模式,非阻塞模式下,如果调用recv()没有接收到任何数据,或send()无法发送数据,将引起socket.error异常

No.3 TCP的三次握手和四次挥手

No.4 TCP收发数据

客户端

from socket import *

# 创建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的信息
server_ip = input("请输入服务器ip:")
server_port = int(input("请输入服务器port:"))
# 链接服务器
tcp_client_socket.connect((server_ip, server_port))
# 提示用户输入数据
send_data = input("请输入要发送的数据:")
tcp_client_socket.send(send_data.encode("gbk"))
# 接收对方发送过来的数据,最大接收1024个字节
recvData = tcp_client_socket.recv(1024)
print(‘接收到的数据为:‘, recvData.decode(‘gbk‘))
# 关闭套接字
tcp_client_socket.close()

服务端

from socket import *

# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 绑定
tcp_server_socket.bind((‘‘,9420))
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcp_server_socket.listen(128)
# 等待连接,产生一个新的socket
client_socket, clientAddr = tcp_server_socket.accept()
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024)  # 接收1024个字节
print(‘接收到的数据为:‘, recv_data.decode(‘gbk‘))
# 发送一些数据到客户端
client_socket.send("thank you !".encode(‘gbk‘))
# 关闭套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
client_socket.close()
tcp_server_socket.close()

No.5 TCP文件下载

客户端

from socket import *

def main():
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    server_ip = input("请输入服务器ip:")
    server_port = int(input("请输入服务器port:"))
    tcp_client_socket.connect((server_ip, server_port))
    file_name = input("请输入要下载的文件名:")
    tcp_client_socket.send(file_name.encode("utf-8"))
    msg = ‘‘
    while True:
        recv_data = tcp_client_socket.recv(1024)
        msg += recv_data.decode(‘utf-8‘)
        if len(recv_data) < 1024:
            break
    if msg:
        with open(file_name + ‘bak‘, "w") as f:
            f.write(msg)

    tcp_client_socket.close()

if __name__ == "__main__":
    main()

服务端

from socket import *
import sys

def get_file_content(file_name):
    """获取文件的内容"""
    try:
        with open(file_name, "rb") as f:
            content = f.read()
        return content
    except:
        print("没有下载的文件:%s" % file_name)

def main():
    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    tcp_server_socket.bind((‘‘,9420))
    tcp_server_socket.listen(128)

    while True:
        client_socket, clientAddr = tcp_server_socket.accept()
        recv_data = client_socket.recv(1024)
        file_name = recv_data.decode("utf-8")
        print("对方请求下载的文件名为:%s" % file_name)
        file_content = get_file_content(file_name)
        if file_content:
            client_socket.send(file_content)
        client_socket.close()
    tcp_server_socket.close()

if __name__ == "__main__":
    main()

No.6 TCP的长连接和短连接

TCP长连接

client向server发起连接

server接收到请求,双方建立连接

client向server发送消息

server回应client

一次读写完毕,连接继续

直到client发起关闭请求

TCP短连接

client向server发起连接

server接收到请求,双方建立连接

client向server发送消息

server回应client

一次读写完成,client发起断开连接请求

TCP长/短连接的工作流程

长连接


短连接

TCP长/短连接的优缺点

长连接可以省去较多的TCP创建和关闭的操作,减少浪费,节约时间,对于频繁请求资源的场景来说,适合用长连接,但是随着客户端连接越来越多,server端早晚扛不住,这时候就需要采取一些策略,例如关闭一些长时间没有读取的连接,这样可以避免恶意连接,还可以限制每个客户端的最长连接数,这样可以避免某个客户端拖后腿,短连接控制简单,不需要控制手机,但是如果客户频繁的请求资源,那就比较操蛋了,浪费时间,浪费带宽

TCP长/短连接的适用场景

长连接适用于操作频繁,点对点的的通讯,而且连接数不是太多的情况,每个TCP需要三次握手,如果每个操作都是先连接,再操作,会浪费很长的时间,所以每个操作之后我们就不给它断开,再次操作直接发送请求就可以了,例如,数据库

像WEB网站的http服务一般采用短连接,因为长连接对服务器占用的资源太多,而且http服务的连接数一般不会太少,服务器难说能扛得住,所以并发量高的场景,最好采用短连接

No.7 UDP收发数据

from socket import *

udp_socket = socket(AF_INET, SOCK_DGRAM)
dest_addr = (‘‘, 9420)
send_data = input("请输入要发送的数据:")
udp_socket.sendto(send_data.encode(‘utf-8‘), dest_addr)
recv_data = udp_socket.recvfrom(1024)
print(recv_data[0].decode(‘gbk‘))
print(recv_data[1])
udp_socket.close()

No.8 UDP聊天室

import socket

def send_msg(udp_socket):
    msg = input("\n请输入要发送的数据:")
    dest_ip = input("\n请输入对方的ip地址:")
    dest_port = int(input("\n请输入对方的port:"))
    udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))

def recv_msg(udp_socket):
    recv_msg = udp_socket.recvfrom(1024)
    recv_ip = recv_msg[1]
    recv_msg = recv_msg[0].decode("utf-8")
    print(">>>%s:%s" % (str(recv_ip), recv_msg))

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(("", 9420))
    while True:
        print("="*30)
        print("1:发送消息")
        print("2:接收消息")
        print("="*30)
        op_num = input("请输入要操作的功能序号:")
        if op_num == "1":
            send_msg(udp_socket)
        elif op_num == "2":
            recv_msg(udp_socket)
        else:
            print("输入有误,请重新输入...")

if __name__ == "__main__":
    main()

No.9 TCP和UDP

TCP特点

面向连接,通信双方必须建立连接才能进行数据的传输,双方必须为对象分配必要的系统资源,TCP发送的每个报文段都必须得到接收方的应答才认为传输成功,发送端如果在规定时间内没有收到接收端的应答,发送端会将报文段重新发送,TCP还会进行数据校验,还会通过流量控制机制避免主机发送太快而让接收端接收不到数据,完成数据交换后,通信双方必须断开连接,以释放系统资源,这种连接是点对点的,因此TCP不适用广播应用程序

UDP特点

?UDP并不提供对IP协议的可靠机制、流控制以及错误恢复功能等,由于UDP比较简单, UDP头包含很少的字节,比 TCP 负载消耗少,UDP 适用于不需要 TCP 可靠机制的情形,QQ就是采用的UDP协议

通信模型

TCP

UDP

原文地址:http://blog.51cto.com/13559120/2288333

时间: 2024-11-09 00:40:44

Python全栈开发之网络编程的相关文章

Python全栈开发-Day8-Socket网络编程

本节内容 断言 Socket构建框架 ftp构建框架 Socket粘包 Socket介绍 Socket参数介绍 基本Socket实例 通过Socket实现简单SSH SocketServer 支持多用户在线传输的FTP程序 1.断言 断言作用是,下面代码的执行要严格依据上面的执行结果,断言则为判断上面代码的结果是否符合下面代码执行的前提,有点类似于登机安检. assert type(obj.name) is str 上面这句话就是断言,如果断言为真,则继续执行下面代码,如果为假,则报错,错误类别

Python全栈【Socket网络编程】

Python全栈[socket网络编程] 本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" 用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式

Python全栈开发之并发编程

No.1 线程 什么是多任务 就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行 并发和并行 并发是指任务数多余cpu核数,通过操作系统的各种任务调度算法,实现多个任务 并行是指任务数小于cpu核数,即任务同时执行 单线程 import time def say_hello(i): print('hello ', i) if __name__ == '__main__': for i in ra

Python 全栈开发【第一篇】:目录

Python 全栈开发[第0篇]:目录 第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基础语法入门 Python 全栈开发[第三篇]:数据类型.字符编码.文件操作 第二阶段:函数编程&常用标准库 Python 全栈开发[第四篇]:函数.递归.生成器.迭代器 Pyhton 全栈开发[第五篇]:常用模块学习 第三阶段:面向对象编程&网络编程基础 Python 全栈开发[第六篇]:面向对象

python全栈开发学习目录

python全栈开发学习目录 第一章 计算机基础 第二章Python入门 第三章数据类型 第四章文件操作 第五章函数 第六章 模块 第七章 面向对象 第八章 网络编程 第九章 并发编程 第十章 数据库 第十一章 前端开发-html 第十一章 前端开发-css 附加:js特效 15个小demo 第十一章 前端开发-JavaScript 第十一章 前端开发-jQuery 第十一章 前端开发-bootstrap 第十二章 Django框架开发 ... 原文地址:https://www.cnblogs.

Python全栈开发【基础四】

Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 匿名函数 lambda表达式:对于简单的函数,存在一种简便的表示方式,即lambda表达式 1 #这段代码 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #换成匿名函数 7 calc = lambda n:n**n 8 print(calc(10)) 匿名函数主要是和其它函数搭配使用 举例: 1 ########

自学Python全栈开发第一次笔记

我已经跟着视频自学好几天Python全栈开发了,今天决定听老师的,开始写blog,听说大神都回来写blog来记录自己的成长. 我特别认真的跟着这个视频来学习,(他们开课前的保证书,我也写了一份,哈哈哈...)我现在是准大学生,准备学习编程,日后做一个程序员,哈哈哈.听说程序员很苦逼,不过貌似挣得也很多啊.并且我貌似也只喜欢计算机这个方面,所以我想在这个行业发光. 前些天学习了一些Linux一些命令: pwd     查看你当前所在的目录  /root=计算机/E盘 /    是根目录 cd(ch

Python全栈开发记录_第一篇

Python全栈开发记录只为记录全栈开发学习过程中一些难和重要的知识点,还有问题及课后题目,以供自己和他人共同查看.(代码行数:70行) 知识点1:优先级:not>and 短路原则:and:如果第一个条件的结论为假,那么 and 前后两个条件组成的表达式计算结果一定为假,后面的条件计算机不会进行计算 or:如果第一个条件的结论为真,那么or 前后两个条件组成的表达式计算结果一定为真,后面的条件计算机不会进行计算 知识点2:python区分大小写,常量需全部字母大写(默认这样写) python换行

Python全栈开发【基础三】

Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 1 def 函数名(参数): 2 3 ... 4 函数体 5 ... 6 返回值 函数的定义主要有如下要点: def:表示函数的关键字 函数名:函数的名称,日后根据函数名调用函数 函数体:函数中进行一系列的逻辑计算 参数:为函数体提供数据 返回值:当函数执行完毕后,可以给调用者返回数据. 总结使用函数的好处: 1.减少代码重用 2.保持一致性,易维护