python 网络编程 速度_python 网络编程

网络编程:

自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了。

计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信。

网络编程就是如何在程序中实现两台计算机的通信。

举个例子,当你使用浏览器访问新浪网时,你的计算机就和新浪的某台服务器通过互联网连接起来了,然后,新浪的服务器把网页内容作为数据通过互联网传输到你的电脑上。

网络通信是两台计算机上的两个进程之间的通信。

由于你的电脑上可能不止浏览器,还有QQ、Skype、Dropbox、邮件客户端等,不同的程序连接的别的计算机也会不同,所以,更确切地说,网络通信是两台计算机上的两个进程之间的通信。比如,浏览器进程和新浪服务器上的某个Web服务进程在通信,而QQ进程是和腾讯的某个服务器上的某个进程在通信。

网络编程对所有开发语言都是一样的,Python也不例外。用Python进行网络编程,就是在Python程序本身这个进程内,连接别的服务器进程的通信端口进行通信。

1 什么是协议

计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM、Apple和Microsoft都有各自的网络协议,互不兼容,这就好比一群人有的说英语,有的说中文,有的说德语,说同一种语言的人可以交流,不同的语言之间就不行了。为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现互联网这个目标,就需要使用互联网协议簇(Internet Protocol Suite)就是通用协议标准。

Internet是由inter和net两个单词组合起来的,原意就是连接“网络”的网络,有了Internet,任何私有网络,只要支持这个协议,就可以联入互联网。因为互联网协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简TCP/IP协议。

2 TCP/IP协议族

TCP/IP提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。

它通常将软件通信过程抽象化为四个抽象层,采取协议堆栈的方式,分别实现出不同通信协议。协议套组下的各种协议,依其功能不同,被分别归属到这四个层次结构之中,常被视为是简化的七层OSI模型。

OSI模型,即开放式通信系统互联参考模型(Open System Interconnection Reference Model),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。

链路层:处理与电缆或其他传输媒介的物理接口

网络层:处理数据在网络中的活动

ip协议【网络互连协议】

用途:将多个包在网络中联系起来,传输数据包(不可靠传输),最基本功能就是寻址和分段功能,不提供端到端,路由到路由的确认,不提供重发和流量控制。是计算机网络能够相互通信的基本规则。出错则像ICMP报告,ICMP在IP模块中实现

ICMP协议

用途:面向无连接协议,用于传输错误报告控制信息(控制信息是指网络不通畅,主机是否到达,路由是否可用的这些网络本身的消息,不涉及用户传输的数据)

ARP协议->地址解析协议

用途:根据IP地址获取物理地址的协议(即MAC地址)。在同一子网内通过ARP协议可以实现数据包的互相传递。不在一个子网内则无法获得MAC地址,只有通过网关去处理。

RARP协议->反转地址协议

用途:和ARP协议相反,将主机的物理地址转换成IP地址。

传输层:提供两台主机间端到端的通信

TCP协议->传输控制协议

用途:面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)传输层协议。

UDP协议->用户数据协议

用途:无连接,不保证可靠的传输层协议。

应用层:用于不同的应用程序

NAT协议->网络地址转换协议【放在这里不完全合适】

用途:实现内网IP地址和公网地址之间的相互转换。将大量的内网IP转换成一个或者少量的公网IP

FTP协议->文件传输协议

用途:通过FTP协议在FTP客户端访问FTP服务端,默认使用20和21端口,20用于传输数据,21用于传输控制信息。

HTTP协议->超文本传输协议

用途:是用于从WWW服务器传输超文本到本地浏览器的传输协议。是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。

TELNET协议

用途:是Internet远程登陆服务的标准协议和主要方式,为用户提供了在本地计算机上完成远程主机工作的能力。

SMTP协议->简单邮件传输协议

用途:控制邮件传输的规则,以及邮件的中转方式。

DNS协议

用途:定义域名规则,将域名和IP相互映射

3.IP地址

一个程序如何在网络上找到另一个程序?

首先,程序必须要启动,其次,必须有这台机器的地址,我们都知道我们人的地址大概就是国家\省\市\区\街道\楼\门牌号这样字。那么每一台联网的机器在网络上也有自己的地址,它的地址是怎么表示的呢?

就是使用一串数字来表示的,例如:100.4.5.6

IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。

4.端口

那么TCP/IP协议中的端口指的是什么呢?

端口就好一个房子的门,是出入这间房子的必经之路。

端口号

端口是通过端口号来标记的,端口号只有整数,范围是从0到65535(2的16次方)

系统预留端口号

预留端口号是广泛使用的端口号,方位从0-1023 开发中不要使用

如http的80端口 ftp的21端口

总结:

通过IP在网络内寻找主机、通过端口寻找主机中的应用程序

即:ip地址精确到具体的一台电脑,而端口精确到具体的程序。

socket:

本地的进程间通信有很多种方式,例如队列、同步(互斥锁、条件变量等)

以上通信方式都是在一台机器上不同进程之间的通信方式,那么问题来了网络中进程之间如何通信?

网络中进程之间如何通信

主要解决的问题是如何唯一标识一个进程,否则通信无从谈起!

在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。

其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。

这样利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互

什么是socket

socket(简称套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:

它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于Socket来完成通信的。

例如我们每天浏览的、QQ 聊天、收发Email等等

创建socket

在Python中使用socket模块的函数socke就可以完成:socket.socket(AddressFamily, Type)

说明:

函数socket.socket创建一个socket,返回该 socket的描述符,该函数带有两个参数:

Address Family:可以选择AF_INET(用于 Internet 进程间通信)或者AF_UNIX(用于同一台机器进程间通信)

实际工作中常用AF_INET

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

eg:

import socket

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

print("socketCreated")

print(s)

s2 = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

print("socketCreated")

print(s2)

常用方法

socket套接字常用操作

s.bind() 绑定(主机名称、端口)到一个套接字上

s.listen() 设置并启动TCP监听

s.accept() 等待客户端连接

s.connect() 连接指定服务器

s.recv() 接受TCP消息

s.send() 发送TCP消息

s.recvfrom() 接受UDP消息

s.sendto() 发送UDP消息

s.close() 关闭套接字对象

UDP编程

TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。

使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。

虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。

适用情况

UDP是面向消息的协议,通信时不需要建立连接,数据的传输当然是不可靠的,UDP一般用于多点通信和实时的数据业务,例如:

语音广播、视频、QQ、TFTP(简单文件传送)、SNMP(简单网络管理协议)、RIP(路由信息协 议,如:报告股票市场,航空信息)

DNS(域名解释)

服务端实现:

import socket

server_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

s_addr = ("127.0.0.1",8080)

server_socket.bind(s_addr)

print("服务器连接成功!")

while True:

data,addr = server_socket.recvfrom(1024)

print(data.decode("utf-8"))

server_socket.close()

客户端实现:

import socket

client_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

addr = ("127.0.0.1",8080)

message = "Good morning! Saturday!!!"

client_socket.sendto(message.encode("utf-8"),addr)

client_socket.close()

TCP编程

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,"打电话""

tcp服务器

在程序中,如果想要完成一个tcp服务器的功

能,需要的流程如下:

1. socket创建一个套接字

2. bind绑定ip和port

3. listen使套接字变为可以被动链接

4. accept等待客户端的链接

5. recv/send接收发送数据

三次握手,四次挥手

TCP 连接三次握手

TCP 三次握手就好比两个人在街上隔着50米看见了对方,但是因为雾霾等原因不能100%确认,所以要通过招手的方式相互确定对方是否认识自己。

张三首先向李四招手(syn),李四看到张三向自己招手后,向对方点了点头挤出了一个微笑(ack)。张三看到李四微笑后确认了李四成功辨认出了自己(进入estalished状态)。

但是李四还有点狐疑,向四周看了一看,有没有可能张三是在看别人呢,他也需要确认一下。

所以李四也向张三招了招手(syn),张三看到李四向自己招手后知道对方是在寻求自己的确认,于是也点了点头挤出了微笑(ack),李四看到对方的微笑后确认了张三就是在向自己打招呼(进入established状态)。

我们看到这个过程中一共是四个动作,张三招手--李四点头微笑--李四招手--张三点头微笑。

其中李四连续进行了2个动作,先是点头微笑(回复对方),然后再次招手(寻求确认),实际上可以将这两个动作合一,招手的同时点头和微笑(syn+ack)。

于是四个动作就简化成了三个动作,张三招手--李四点头微笑并招手--张三点头微笑。这就是三次握手的本质,中间的一次动作是两个动作的合并。

TCP数据传输

TCP 数据传输就是两个人隔空对话,差了一点距离,所以需要对方反复确认听见了自己的话。

张三喊了一句话(data),李四听见了之后要向张三回复自己听见了(ack)。

如果张三喊了一句,半天没听到李四回复,张三就认为自己的话被大风吹走了,李四没听见,所以需要重新喊话,这就是tcp重传。

TCP 四次挥手

TCP断开链接的过程和建立链接的过程比较类似,只不过中间的两部并不总是会合成一步走,所以它分成了4个动作,张三挥手(fin)——李四伤感地微笑(ack)——李四挥手(fin)——张三伤感地微笑(ack)。

服务端实现:

import socket

#socket创建套接字

server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s_addr = ("127.0.0.1",8083)

#bind绑定ip和端口

server_socket.bind(s_addr)

#listen控制最大监听数

server_socket.listen(100)

# accept等待客户端的连接

client_socket, c_addr = server_socket.accept()

while True:

print(client_socket,c_addr)

print("连接成功!")

data = client_socket.recv(1024)

msg = data.decode("utf-8")

print("接收到的消息为:",msg)

message = input("请输入信息:")

bytes = message.encode("utf-8")

client_socket.send(bytes)

print("发送消息成功!")

server_socket.close()

客户端实现:

import socket

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

c_addr = ("127.0.0.1",8083)

client_socket.connect(c_addr)

print("连接成功!")

while True:

message = input("请输入信息:")

bytes = message.encode("utf-8")

client_socket.send(bytes)

print("发送信息成功!")

data = client_socket.recv(1024)

msg = data.decode("utf-8")

print("接收到的消息为:",msg)

client_socket.close()

多进程、多线程网络通信

服务端实现:

import socket

from multiprocessing import Process

s_addr = ("127.0.0.1",8084)

def handle_client(client_socket):

try:

data = client_socket.recv(1024)

print("接收到的消息为:", data.decode("utf-8"))

except Exception as e:

print(e)

if __name__ == '__main__':

server_socket = None

try:

server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

server_socket.bind(s_addr)

server_socket.listen(100)

print("服务器创建连接成功!")

while True:

client_socket, addr = server_socket.accept()

print(client_socket, addr)

p = Process(target=handle_client,args=(client_socket,))

p.start()

except Exception as e:

print("服务器连接失败")

finally:

if server_socket != None:

server_socket.close()

客户端1实现:

import socket

client_socket = None

try:

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

c_addr = ("127.0.0.1",8084)

client_socket.connect(c_addr)

while True:

message = input("请输入信息:")

bytes = message.encode("utf-8")

client_socket.send(bytes)

print("发送信息成功!")

# data = client_socket.recv(1024)

# msg = data.decode("utf-8")

# print("接收到的信息为:",msg)

except Exception as e:

print(e)

finally:

if client_socket != None:

client_socket.close()

客户端2实现:

import socket

client_socket = None

try:

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

c_addr = ("127.0.0.1",8084)

client_socket.connect(c_addr)

while True:

message = input("请输入信息:")

bytes = message.encode("utf-8")

client_socket.send(bytes)

print("发送信息成功!")

data = client_socket.recv(1024)

msg = data.decode("utf-8")

print("接收到的信息为:",msg)

except Exception as e:

print(e)

finally:

if client_socket != None:

client_socket.close()

tcp通信

服务端实现:

import socket,threading

server_socket = None

users = dict() # 建立一个用户空字典

def add_user(client, addr):

global users

users[addr] = client

print("添加新用户")

def func(client, addr):

while True:

try:

message = client.recv(1024)

for key, val in users.items():

if key != addr:

val.send(message)

except Exception as e:

# raise e

print("发送消息失败", e)

if __name__ == '__main__':

try:

server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s_addr = ("127.0.0.1",8055)

server_socket.bind(s_addr)

server_socket.listen(2)

print("服务器创建连接成功!")

for i in range(2):

client, addr = server_socket.accept()

add_user(client, addr) # 将新用户添加到在线用户列表

t = threading.Thread(target=func, args=(client, addr))

t.start()

input()

except Exception as e:

print("服务器连接失败",e)

finally:

if server_socket is not None:

server_socket.close()

客户端实现:

import socket,threading

c_addr = ("127.0.0.1",8055)

def menu():

menu = """

请选择你要的操作:\n

【1】选择I输入信息\n

【2】选择O查看信息\n

"""

select =input(menu)

return select

def send_msg(client_socket):

try:

msg = input("请输入内容:")

client_socket.send(msg.encode("utf-8"))

except Exception as e:

print("发出错误信息",e)

msg_box = []

lock = threading.Lock()

def func(client_socket):

try:

while True:

data = client_socket.recv(1024)

msg = data.decode("utf-8")

lock.acquire()

msg_box.append(msg)

lock.release()

except Exception as e:

print(e)

def show_receie_msgs():

lock.acquire()

while len(msg_box) != 0:

e =msg_box.pop(0)

print(e)

lock.release()

if __name__ == '__main__':

client_socket = None

try:

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client_socket.connect(c_addr)

t_receiver = threading.Thread(target=func,args=(client_socket,))

t_receiver.start()

while True:

select = menu()

if select == "I":

send_msg(client_socket)

elif select == "O":

show_receie_msgs()

else:

print("选项不正确!")

except Exception as e:

print("连接服务器失败",e)

finally:

client_socket.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值