Python 网络编程(1):TCP 编程(socket)简介

0. 框架

Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络

使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。

一个Socket就是由IP地址和端口号(范围是0~65535)组成,可以把Socket简单理解为IP地址加端口号

因此,当Socket连接成功地在服务器端和客户端之间建立后:

  • 服务器端来说,它的Socket是指定的IP地址和指定的端口号;
  • 客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

1. 理论

1.1 进程/线程

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。

有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)

在这里插入图片描述
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。

操作系统轮流让各个任务交替执行任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

1.2 网络编程

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

网络编程就是如何在程序中实现两台计算机的通信
更确切地说,网络通信是两台计算机上的两个进程之间的通信

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

1.3 互联网协议:TCP /IP协议

ip 地址

(1)ip 地址是什么

互联网上每个计算机的唯一标识就是IP地址,类似123.123.123.123

如果一台计算机同时接入到两个或更多的网络,比如路由器,它就会有两个或多个IP地址,所以,IP地址对应的实际上是计算机的网络接口,通常是网卡

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

(2)ip 地址的作用

IP协议负责把数据从一台计算机通过网络发送到另一台计算机。

数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。

IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证顺序到达

TCP 协议

TCP(Transmission Control Protocol)传输控制协议

TCP协议则是建立在IP协议之上的。

TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。

TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发

许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等。

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

端口有什么作用?在两台计算机通信时,只发IP地址是不够的,因为同一台计算机上跑着多个网络程序。一个TCP报文来了之后,到底是交给浏览器还是QQ,就需要端口号来区分。每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。

2. TCP 编程

Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接,而打开一个Socket需要知道目标计算机的IP地址端口号,再指定协议类型即可。

2.1 概述:客户端和服务器

大多数连接都是可靠的TCP连接
创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器

比如用浏览器访问新浪,个人计算机——>客户端;新浪服务器——>服务器。

浏览器会主动向新浪的服务器发起连接。如果一切顺利,新浪的服务器接受了我们的连接,一个TCP连接就建立起来的,后面的通信就是发送网页内容了。

2.2 客户端编程

生成的 sina.html 文件可以直接进入新浪。

注意:

  • 新浪强制HTTPS协议访问 所以 80端口改443 socket 改 ssl
import socket
import ssl       

# 创建一个socket:
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET指定使用IPv4协议(如果要用更先进的IPv6,就指定为AF_INET6);SOCK_STREAM指定使用面向流的TCP协议
s = ssl.wrap_socket(socket.socket())   
s.connect(('www.sina.com.cn', 443))  # 参数是一个tuple,包含地址和端口号

# 发送数据:
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\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('sina.html', 'wb') as f:
    f.write(html)   # 生成一个 sina.html文件

2.3 服务器编程

分别在不同的两个终端,先后执行server.pyclient.py,最后会在客户端出现以下结果:
在这里插入图片描述

在这里插入图片描述

  • 服务器端(server.py)
# -*- coding: utf-8 -*-
#server.py
import socket,threading,time
#创建一个基于IPv4和TCP协议的Socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 监听端口:
s.bind(('127.0.0.1', 9999))

s.listen(5)
print('Waiting for connection...')

#每个连接都必须创建新线程(或进程)来处理,
#否则,单线程在处理连接的过程中,无法接受其他客户端的连接:
def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)

#服务器程序通过一个永久循环来接受来自客户端的连接,
#accept()会等待并返回一个客户端的连接:

while True:
    # 接受一个新连接:
    sock, addr = s.accept()
    # 创建新线程来处理TCP连接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()
  • 客户端(client.py)
# -*- coding: utf-8 -*-
#client.py
#要测试这个服务器程序,我们还需要编写一个客户端程序:
# 导入socket库:
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()

附:

服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址
127.0.0.1是一个特殊的IP地址,表示本机地址,如果绑定到这个地址,客户端必须同时在本机运行才能连接,也就是说,外部的计算机无法连接进来。

端口号需要预先指定。因为我们写的这个服务不是标准服务,所以用9999这个端口号。请注意,小于1024的端口号必须要有管理员权限才能绑定.

参考:
本文主要是参考 网络编程- 廖雪峰的官方网站TCP编程所做的一些记录。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值