python学习笔记(三十二) -- TCP\IP概念、TCP\UDP编程

版权声明:weixin_40247263的博客 https://blog.csdn.net/weixin_40247263/article/details/82586967

Table of Contents

 

TCP\IP概念

TCP

UDP


TCP\IP概念

计算机之间通信需要统一通信的标准,才可以通信。就像不同国家的人说不同的语言是无法交流的。

TCP\IP协议就是通信的标准。

其中IP协议用来发送数据,它将数据划分为多个数据包,然后通过网络进行传输,数据包会经过多个路由器从一台计算机到另外一台计算机,其中路由器来控制每一个数据包传输的线路,所以就会导致数据包的到达顺序与原发送时的顺序不一样。

IP协议又分为IPV4和IPV6

P地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读。

IPv6地址实际上是一个128位整数,它是目前使用的IPv4的升级版,以字符串表示类似于2001:0db8:85a3:0042:1000:8a2e:0370:7334。


TCP

TCP协议,负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。

一个TCP报文除了包含要传输的数据外,还包含源IP地址和目标IP地址,源端口和目标端口。

端口:每一个计算机会有很多个接入网络的程序,为了区分这些程序使用ip地址+端口号来作为一个网络程序的唯一标识。

例一:

下面使用socket模块,实现通过tcp协议向百度服务器发送get方式的请求,并获取返回内容。

# encoding=utf-8
import socket


# AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6, SOCK_STREAM指定使用面向流的TCP协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('www.baidu.com', 80))
# 以get方式使用http协议向百度发送请求:
s.send(b'GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n')
# 接收数据:
buffer = []
while True:
    # 每次最多接收1k字节:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
# 关闭连接:
s.close()
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# 把接收的数据写入文件:
with open(r'D:\sina.html', 'wb') as f:
    f.write(html)

效果如下 

我们可以发现图片并没有显示出来。我们看一下页面的源码

可以发现,这个图片前面缺少了http:  这几个字符,所以显示不出来。

以后爬取图片的时候一定要对爬取下来的源码进行字符串的拼接。

例二:

模拟一个客户端和服务端的交互

服务端代码如下:

# encoding=utf-8
import socket
import threading
import time


def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr) # addr是一个元组,包含ip和端口号
    #  通过客户端的socket 给客户端发送信息,注意网络间的通信本质传递的是二进制数据
    #  所以发送的应该是byte类型的数据
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)  # 接收客户端发送过来的数据
        time.sleep(1)   # 让线程等待1s再执行
        if not data or data.decode('utf-8') == 'exit':
            break
        # 在客户端发送过来的数据前面加上Hello
        # 注意同样发送过去的必须是byte类型的数据
        sock.send(('Hello,%s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()  # 关掉客户端的socket
    print('Connection from %s:%s closed.' % addr)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip和端口,如果ip为0.0.0.0则绑定所有网卡:
s.bind(('127.0.0.1', 9999))
# 开始监听
s.listen(5)

while True:
    print('Waiting for connection...')
    # 接收连接,通过服务端的socket接收客户端发送过来的请求,返回一个客户端的socket以及客户端的ip
    sock, addr = s.accept()  # 这里如果没有接收到连接,会阻塞在这里,不会执行下面的代码
    print('get a connection')
    # 创建出来一个线程来去回应客户端
    # 这里使用多线程的目的就是为了能够同时给多个客户端做出回应
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

客户端代码如下:

import socket


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s.connect(('127.0.0.1', 9999))
# 接收欢迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 发送数据:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

UDP

TCP的特点就是保证数据能够发送给对方,因为其先建立连接,再发送数据,如果过程中数据丢失还会重新发送,其实TCP还有三次握手确认,想了解的自行百度。

而UDP的特点就是传输效率高,效率高的原因是因为它不会去建立连接,你告诉它把数据发送到哪个ip地址,哪个端口号,它就直接传输了,数据丢失也不会重新发送。

下面是UDP协议使用的案例:

服务端

# encoding=utf-8
import socket
import threading


def udplink(data, addr):
        print('Received from %s:%s.' % addr)
        # 向客户端发送数据
        s.sendto(b'Hello, %s!' % data, addr)


# socket.SOCK_DGRAM 就代表使用UDP协议
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
s.bind(('127.0.0.1', 9999))
# 接收数据
# 注意这里和TCP的区别
# TCP是先获取连接,返回一个客户端的socket,再接收数据
# 这里直接通过客户端的socket接收数据
while 1:  # 这里我用 1代替了True,原因是 1效率更高
    data, addr = s.recvfrom(1024)  # 这里如果没有接收到数据也会阻塞
    t = threading.Thread(target=udplink, args=(data, addr))
    t.start()

客户端

import socket


s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 发送数据:
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收数据:
    print(s.recv(1024).decode('utf-8'))
s.close()

猜你喜欢

转载自blog.csdn.net/weixin_40247263/article/details/82586967
今日推荐