如何唯一标识一个进程?
在1台电脑上可以通过进程**进程号(PID)**来唯一标识一个进程。
在TCP/IP协议族中,网络层的**“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”**可以唯一标识主机中的应用进程(进程)。
利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是,它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的。
import socket
socket.socket(AddressFamily, Type)
函数 socket.socket 创建一个 socket,该函数带有两个参数:
Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
Type:套接字类型,可以是SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者SOCK_DGRAM(数据报套接字,主要用于
UDP 协议)
import socket
# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ...这里是使用套接字的功能(省略)...
# 不用的时候,关闭套接字
s.close()
套接字使用流程 与 文件的使用流程很类似
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据包协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
创建一个udp客户端程序的流程具体步骤如下:
#coding=utf-8
from socket import *
# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 准备接收方的地址
# '192.168.1.103'表示目的ip地址
# 8080表示目的端口
dest_addr = ('192.168.1.103', 8080) # 注意 是元组,ip是字符串,端口是数字
# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 4. 发送数据到指定的电脑上的指定程序中
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)
# 5. 关闭套接字
udp_socket.close()
#coding=utf-8
from socket import *
# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 准备接收方的地址
dest_addr = ('192.168.236.129', 8080)
# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 4. 发送数据到指定的电脑上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)
# 5. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
# 6. 显示对方发送的数据
# 接收到的数据recv_data是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])
# 7. 关闭套接字
udp_socket.close()
str->bytes:encode编码
bytes->str:decode解码
字符串通过编码成为字节码,字节码通过解码成为字符串。
其中decode()与encode()方法可以接受参数,其声明分别为:
bytes.decode(encoding="utf-8", errors="strict")
str.encode(encoding="utf-8", errors="strict")
其中的encoding是指在解码编码过程中使用的编码(此处指“编码方案”是名词),errors是指错误的处理方案。
一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行次程序端口可能会发生变化。
一个udp网络程序,也可以绑定信息**(ip地址,端口号)**,如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的。
#coding=utf-8
from socket import *
# 1. 创建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 7788) # ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)
# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
# 4. 显示接收到的数据
print(recv_data[0].decode('gbk'))
# 5. 关闭套接字
udp_socket.close()
TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
双方间的数据传输都可以通过这一个连接进行。
完成数据交换后,双方必须断开此连接,以释放系统资源。
(1)TCP采用发送应答机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
(2)超时重传
发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。
(3)错误校验
TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
( 4 )流量控制和阻塞管理
#coding=utf-8
import socket
def handle_client(client_socket):
"为一个客户端进行服务"
recv_data = client_socket.recv(1024).decode("utf-8")
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
# 组织相应 头信息(header)
response_headers = "HTTP/1.1 200 OK\r\n" # 200表示找到这个资源
response_headers += "\r\n" # 用一个空的行与body进行隔开
# 组织 内容(body)
response_body = "hello world"
response = response_headers + response_body
client_socket.send(response.encode("utf-8"))
client_socket.close()
def main():
"作为程序的主控制入口"
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 允许在7788端口资源没有彻底释放完毕时,可以重复绑定7788端口
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 7788))
server_socket.listen(128)
while True:
client_socket, client_addr = server_socket.accept()
handle_client(client_socket)
# 主程序
if __name__ == "__main__":
main()