《Python网络基础》学习笔记(一)-客户/服务器网络介绍

 TCP基础

1、TCP/IP实际上是一些协议的合集。

2、为了实现数据的共享,TCP是通过把要发送的数据流分解为很多小信息包在网络上传输,而这些信息包在接收者这方会重新合成在一起。

3、寻址

为了保证分解后能够正确的传输,TCP必须要满足一定的要求。首先,TCP要能够知道远程机器的IP地址,其次TCP需要知道是与远程机器上正在运行的哪个程序进行通信,为此TCP需要使用端口号来标记应用程序,每个程序有一个唯一的端口号。其中,有些端口号是事先就知道的,而有些则是随机指定的。

尽管知道了IP地址和端口号,TCP就可以正常工作了,但是要让我们记住一串诸如202.108.22.5这样的数字是很困难的,所以出现了今天的DNS(Domain Name System,域名系统),当用户想要和一个远程机器建立连接时,只需要输入该机器IP地址对应的域名地址,DNS服务器就会为你找到该域名对应的IP地址,接下来就可以建立起连接了。

4、可靠性

TCP是一个可靠的协议,它通过以下几个规则来实现此特性。

(1).为了防止数据在传输的过程中被损坏,每个信息包都会包含一个校验码,当信息包到达目的地的时候,接收方会对比校验码和收到的信息中的数据,如果校验码不对,那么该信息包将会被丢弃。

(2).为了防止信息包的丢失,TCP会要求接收方没收到一个信息包都反馈一下,如果接收方没有提供反馈,那么发送方会自动重新发送一次。TCP会一直尝试着发送信息包,直到接收者发送了一个反馈信号,或者由TCP判断出网络连接出现了问题并返回一个错误提示

(3).为了防止信息包的重复或者顺序错误,TCP每传送一个信息包都会传送一个序号,接收方会检查这个序号,并且把全部信息包按照序号顺序重新进行合并。

5、路由

信息包要从我们的电脑上到达远程的服务器上,一定会经过很多很多不同的网络,在这个过程中,负责接收信息包并且决定通过什么样的途径将它们传输到目的地的设备就是没有它我会死的路由器。

6、安全

路由器和本地网络的一个重要功能是安全。为了保证信息包在传输的过程中不被拦截和修改,程序员发明了SSL(Secure Sockets Layer,安全套接层)和TLS(Transport Layer Security,TLS)。SSL一般是建立在TCP连接之上,提供服务器的认证、加密和数据完整性功能,而TLS的原理与之十分类似


客户/服务端模式

在客户/服务端结构下,服务器一直在侦听来自客户端的请求,有请求后,就建立连接来处理它们。例如,当打开一个浏览器并访问www.baidu.com的时候,浏览器会连接www.baidu.com的服务器,并且请求访问www.baidu.com这一页。服务器按照顺序找到这一页,并把它传送回客户端,即我们的浏览器,这样浏览器就能按照一定的格式显示出来。

1.服务器端端口号

在客户/服务器模式中,服务器通常是侦听一个大家都知道的端口号,比如在上面那个例子中,Web服务器会侦听80端口。在www.iana.com上有一份有国际因特网地址分配委员会维护的官方已分配的端口列表。一般说来,系统会占用小于1024的端口,所以如果我们编写了一个服务器,那么我们就应该选择一个大于1024且小于65535的端口来对它进行访问,这样可以尽量避免和其他服务产生冲突。

2.客户端端口号

客户端端口号不是很重要。通常情况下客户端会有操作系统随机挑选一个没有被使用的端口号,当服务器收到一个连接请求的时候,这个请求中会带有客户端的端口号,因此数据会被传输到这个端口上。


UDP基础

除了TCP以外,还有一种协议被广泛使用:UDP。它只能保证数据是完整的,但是不能保证数据是否真的被收到,也不能保证收到数据的顺序和发送时候是一样的。

应该使用TCP的情况:

1.需要可靠的数据连接

2.需要发送较多的数据

3.可以容忍初始连接时的短暂延迟

应该使用UDP的情况:

1.不关心信息包是否到达、不要求信息包严格完整

2.需要尽快建立网络会话

3.只传送少量数据。UDP对信息包的大小做出了限制:不能超过64KB,而通常人们只用UDP传送1KB以下的数据


Python网络编程

1.底层接口

Python提供了访问底层操作系统Socket接口的全部方法。

import socket,sys

port = 70#使用端口70
host = sys.argv[1]
filename = sys.argv[2]

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))

s.sendall(filename + "\r\n")

while 1:
    buf = s.recv(2048)
    if not len(buf):
        break;
    sys.stdout.write(buf)

这是在现实世界中存在的可以运行的网络协议实现的最小程序,它实现的是Gopher协议,一种Web出现之前在Internet上非常流行的协议,这个程序需要两个命令行参数:主机名和文件名,实现从主机上请求相关文档的功能。

它通过调用socket.socket()来建立一个Socket,参数告诉系统需要一个Internet socket来进行TCP通信。然后程序连接远程主机并提供文件名,最后获得响应后,在屏幕上打印出来

将上述代码保存为gopherclient.py,然后在Powershell中运行

PS C:\Users\Tamarous\Desktop> python gopherclient.py quux.org whatsnew.txt

运行结果如下:


2.一个基本的服务器程序

import socket
host=''
port=51423
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host,port))
s.listen(1)

print "Server is running on port %d;press Ctrl-C to terminate." %port
while 1:
    clientsock,clientaddr=s.accept()
    clientfile=clientsock.makefile('rw',0)
    clientfile.write("welcome,"+str(clientaddr)+'\n')
    clientfile.write("Please enter a string:")
    line=clientfile.readline().strip()
    clientfile.write("You entered %d characters.\n" %len(line))
    clientfile.close()
    clientsock.close()

第四行调用socket.socket()来建立一个socket并赋值给s,调用格式为socket.socket(domain, type, protocol)。domain参数的值可以为:

AF_UNIX,AF_LOCAL,AF_INET,PF_UNIX,PF_LOCAL,PF_INET。这几个值中AF_UNIX=AF_LOCAL, PF_UNIX=PF_LOCAL, AF_LOCAL=PF_LOCAL, AF_INET=PF_INET。一般来说,AF 表示ADDRESS FAMILY 地址族,PF 表示PROTOCOL FAMILY 协议族,但这两个宏定义是一样的,所以使用哪个都没有关系。参数type指定socket的类型:SOCK_STREAM提供有序、可靠、双向及基于连接的字节流。SOCK_DGRAM支持数据报。SOCK_SEQPACKET提供有序、可靠、双向及基于连接的数据报通信。SOCK_RAW提供对原始网络协议的访问。SOCK_RDM提供可靠的数据报层,但是不保证有序性。protocol一般取0。

setsockopt()的调用格式为s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)。setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。 这个函数中,第一个参数为协议层参数,指明了希望访问一个选项所在的协议栈。通常我们需要使用下面中的一个:

SOL_SOCKET来访问套接口层选项
SOL_TCP来访问TCP层选项
第二个参数是与第一个参数相对应的。第一个参数决定了协议层level,第二个参数决定了该协议层下选项组合。SOL_SOCKET的选项组合如下:
协议层 选项名字
SOL_SOCKET SO_REUSEADDR
SOL_SOCKET SO_KKEPALIVE
SOL_SOCKET SO_LINGER
SOL_SOCKET SO_BROADCAST
SOL_SOCKET SO_OOBINLINE
SOL_SOCKET SO_SNDBUF
SOL_SOCKET SO_RCVBUF
SOL_SOCKET SO_TYPE
SOL_SOCKET SO_ERROR

s.bind((host,port))绑定主机端口

s.listen(1):listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。这里的参数涉及到一些网络的细节。在进程正理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。这里设定为1表示每次最多只有一个等候处理的连接。

while循环从accept()函数开始。程序会在连接了一个客户端后关闭socket。当某个客户端连接的时,accept返回两个信息,一个新的连接客户端socket和客户端的ip地址、端口号。如在上面的例子中添加print语句输出clientsock和clientaddr,你会发现clientsock为socket.socketobject,clientaddr=('客户端Ip',端口)。后面的循环中使用了文件类对象,服务器接着显示出一些介绍性信息,从客户端读一个字符串,显示一个应答,最后关闭客户端socket。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值