您的位置:首页 > 理论基础 > 计算机网络

python(十四)网络编程

2016-05-26 16:41 597 查看
摘要 网络编程是理解TCP/IP协议的基础,也是后期学习HTTP协议的基础,在PHP中对于网络编程基本上没有涉及很多,但是在Python和Java中,网络编程再结合多线程在整个语言中占有重要地位,同时在一些网络抓包,采集等程序中经常使用!

1,网络编程,TCP/IP协议,端口简介

网络编程,也就是通过某种手段实现两台电脑之间互相通信。再详细一点就是,两台电脑之间的通信,其本质是计算机内部两个进程间的通信。比如说QQ,在两台不同的电脑上,启动一个QQ程序就会在当前电脑上开启一个通信的通道,这个通道都是进程,这个进程在电脑上监听着一个位置,等待接受消息和发送消息,同样的另外一台电脑上的QQ也是如此,这样就可以实现通信。

那为了能够使得发送出去的数据可以准确的找到对应接受方的电脑,而且这种动作必须要是全球统一的,于是就制定了一套规范。那计算机只要按这个规范来呢,就能实现相互通信,这个规范就是我们讲的“协议”!

计算机之间的协议有很多,其中最重要的就是我们熟知的TCP/IP协议。

由于在两台电脑之间进行通信的时候,必须知道对方的地址,就像你要给谁写信或者寄件的时候必须写清楚接收方的地址一样。那么IP协议就负责把你要发送的数据准确的找到接受方,当然了,你必须得告诉它接受方的地址。IP协议把数据拆分成IP数据包,一块一块的发送给接受方,但是这里就会产生一个问题,由于IP协议发送出去的数据块,不一定是按顺序到达,也不能保证一定能到达,这样发送出去的数据就不一定会“安全”,而且数据也不一定会完整!

于是就产生了TCP和UDP协议。

TCP和UDP协议都是基于IP协议之上的。

TCP协议是可靠的协议,因为它会保证发送方的数据是按顺序到达,同时也保证数据块不丢失,如果中途丢失了那么就会自动重发。

UDP协议是不可靠的协议,因为它只会帮你把数据包发出去,然后至于能不能到达,这它就不管了。

那么有了安全的TCP为什么还需要不安全的UDP呢?是因为在有些情况下,我们需要数据发送的速度而不在乎数据是否完整,这样由于UDP并不保证数据包的完整性那么它的速度相对TCP来说会快一些。

那么是什么是端口呢?

比如说,A电脑上的QQ要和B电脑上的QQ进行通信。首先光知道对方的IP地址还不够,因为当数据准确到达对方电脑上的时候,还得明确这个数据是要被谁接收的,是被QQ还是电脑上其它的程序。

这样,端口就是用来区分一台电脑上不同的应用程序的!好比,你们住同一个村,但是你们之间还需要不同的门牌号来区分你和别人家!

2,基于TCP协议的网络编程

网络编程回归到程序中的实现是以套接字来描述的,也就是我们说的 Socket 编程。在 python 中通过 socket 模块来实现网络编程。

通过上面的描述,我们也知道,在 Socket 编程中存在“服务器端”和“客户端”,也就是发送方和接受方。

那么在“服务器端”需要做的就是:先打开一个 socket 通道,然后绑定对应的 IP 和端口,然后就开始监听等待着“客户端”的连接。当有客户端连接进来之后,就可以从其中读取数据或者向里面发送数据了。最终,当整个通信结束之后就可以关闭连接了。

相对于“服务器端”,客户端做的事情就显然少了很多,它只需要:打开一个 socket 通道,然后根据给定的 IP 和 端口,连接到“服务器端”,然后同样也可以从里面来读取和发送数据,在最后通信结束之后也同样需要关闭连接。

下面的例子我们先写一个基本的“服务器端”程序,当启动它的时候,它就开始等待着“客户端”的连接,代码如下:





接着,我们就可以继续编写一个“客户端”,当再启动它的时候就会向“服务器端”发送一些数据,并且可以接收从“服务器”端返回回来的数据,如下:





同时,“服务器端”就会有如下的响应:





你看,其实网络编程也没有想象中那么神奇,不是吗?

在上面的代码中有这么一行:

socket.socket(socket.AF_INET, socket.SOCK_STREAM)


这里的两个参数,分别指定了打开一个 socket 通道的时候采用的 IP 协议是那个版本和建立的 socket 通道是属于TCP型还是UDP型。对应的 “socket.AF_INET”是指使用 IP v4 的协议,而“socket.SOCK_STREAM”对应的则是 TCP 协议。

3,基于UDP协议的网络编程

和 TCP 类似,创建一个基于 UDP 协议的服务器端也是需要先打开一个 socket 通道,然后和客户端进行通信,但是这里和TCP方式不同的是,UDP协议的服务器端并不需要去“监听”客户端的连接。

下面是一个简单的 UDP 服务器端程序:





从上面的例子可以看到,基于 UDP 的服务器端程序,在打开一个 socket 通道之后只需要绑定本机对应的 IP 和 端口之后就可以使用 “recvfrom”方法来接收数据了,当需要写数据的时候则是直接调用“sendto”方法,把数据直接写入到指定的“客户端”中!

有了上面的 服务器,我们还是需要一个简单的 客户端,就像是这样:





当启动这个客户端的时候,服务器端的响应如下:





4,一个简单的案例

这个案例也正是我之前写的时候碰到的一个问题,分享一下。

多数情况下,网络编程可以使我们模拟发送请求去获取远端web上面的数据,然后对得到的数据做出分析取出我们真正关心的数据,最后把这些数据做处理,比如说存起来,这就是通常人们说的采集。

那既然我们学习了 socket 编程,就一定可以模拟请求,然后获取到远端web的数据,那么下面的案例就是我们可以模拟请求开源中国站,然后针对返回的数据,我们把数据存储到一个 .html 的本地文件中,这样在本地我们就可以查看开源中国的首页了,当然了,这个是暂时性的!





我们的基本思路是:先创建一个 socket 通道,然后连接上开源中国的主战,然后模拟发送一个 GET 请求,然后循环的去读取返回回来的数据,最后对数据做处理,这里是把它存储到一个本地文件中。

对于模拟发送请求的程序,如果你还是不理解上面的程序,那么你可能需要先去了解一些 HTTP 协议的简单知识。

我要解释的问题是:

当我采用 HTTP 1.1 协议的时候,如果不带 “Connection:Close”头信息,那么后续的 循环读取 数据就会陷入死循环。这是因为 HTTP 1.1 协议中,默认开启了长连接,这样虽然你已经读取完了数据,但是连接还没有关闭,这样就导致了死循环的发生。那么解决方案也比较简单,就是在请求的时候主动设置头信息来关闭长连接,也就是加上头:Connection:Close

----------------------------------------------分割线----------------------------------------------------

一个问题未得到验证,因此需要等验证通过再开始写了 ╮(╯▽╰)╭
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络编程