第一章 客户/服务器网络介绍

本文深入探讨了TCP/IP协议在计算机通信中的作用,包括其作为多个协议集合的基础、信息包的寻址、路由、安全措施、以及在不同网络硬件之间的传输。同时,介绍了Python中使用TCP/IP进行网络编程的方法,涵盖了底层接口、错误处理、文件类对象、服务器操作等关键概念。重点阐述了如何在Python中实现简单的客户端和服务端通信,以及使用高级接口简化网络编程任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TCP/IP是计算机通信的标准协议。
1.1 理解TCP基础
TCP/IP事实上是一些协议的合集,当前大多数使用中的通信都是使用TCP协议。
Internet是在一些共享的线路上发送数据的。为了实现共享,TCP是通过把你要发送的数据流分解成很多小的信息包在Internet上传输的(也许还伴有其它应用程序的信息包),而这些信息包到了接收者再次重新合成在一起。
1.1.1寻址
为了实现信息包计划,TCP必须处理一些细节问题:

  • TCP必须识别远程机器,基于TCP网络,每台机器都有一个唯一的IP,只要知道接收者IP,信息就可以传递过去。
  • TCP必须知道与远程机器运行的哪个程序通信,为了实现这个目的TCP使用端口号每个程序用一个唯一的端口号。

每一个TCP连接的端点是由一个IP地址和一个端口号来唯一识别的。
1.1.2可靠性
在Internet上传送数据会出现错识,出现错识有很多可能:Modem有可能改变了数据的几个字节,某个路由器或许丢失一两个信息包,系统或许收到顺序错识的信息包,一个信息包或许收到两次,再或许网络电缆断了。
TCP是一个可靠协议,这个可靠性通过以下几个规则来实现:

  • 为了防止数据在传输中被损坏,每个信息包都包含一个校验码,当信息到达目的地时接收方会对比较验码和收到的信息中的数据,如果校验码不正确该 消息包被省略。
  • 为了防止信息包丢失,TCP会要求接收方每收到一个信息包都反馈一下,如果接收方没有提供反馈,发送方会自动重发一次,
  • 为了防止信息包重复或顺序错误,TCP每传送一个信息包都会传送一个序号,接收方会检查这个序号,确保收到该信息包,并把全部信息按顺序合并,如果接收方发现一个重复的序号,则该信息包被丢弃。

1.1.3路由
为了能使用信息包顺利地从你的机器传送到远程服务器上,信息包通常会经过很多不同的网络。
在Internet上负责接收信息包将决定如何把它们传输到目地的设备叫路由器。
1.1.4安全
因为信息包在Internet上传输的时候,是通过共享网络传输,所以任何有权使用网络的人都能看到它,这些信息还可能被插入或改写。

  • 当在网络商店购物时,你一定不想你的信用卡账号被陌生人发现。
  • 另外一个潜在风险,你的连接被拦截到另外一台机器。

SSL一般在TCP之上,它提供服务器的认证(你知道和谁通话)、加密(其它人都不能看到你的通信)和数据完整性(传输中信息包没有人能修改)。
1.2 使用客户/服务器模式
在客户端/服务器的通信结构下,服务器一直在侦听来自客户端的请求,有请求后,就建立连接来处理它们。
1.2.1 服务器端端口号
系统端口列表 /etc/services
如果你编写一个服务器,它的服务不在这个列表上,你应该选择一个比1024大,而且在你的机器没有被占用的端口号。最大的端口号可以使用65535。
在Linux系统上只有系统管理员才能访问小于1024端口号。
1.2.2 客户端端口号
客户端会由操作系统随机挑选 一个没有被使用的“短命”的端口号,当服务器接收到请求时,请求中带有客户端的端口号,数据会被传输到该端口号上。
1.3 理解UDP
UDP被用来从一个系统向其它系统传送非常短的消息,它只提供一个保证:那就是你收到的消息是完整的。
UDP用得最广的是DNS系统,另外还常被应用于流式音频和视频应用软件。
使用TCP还是UDP指志方针:
使用TCP

  • 你需要一个可靠的数据传输,以确保你的数据完整无缺地到达目的地。
  • 你的协议需要不止一个请求和服务器的回答。
  • 你要发送较多的数据。
  • 初始连接出现短暂的延迟是可以的。

使用UDP

  • 你不太关心数据包是否到达或不太在意信息包到的顺序是否正确,再或者你自己可以察觉这些问题并自己解决。
  • 你的协议只包括基本的请求和响应。
  • 你需要尽快的建立网络会话。
  • 只传输很少一部分数据,UDP一个限制是一个信息包不超过64KB的数据,通常人们只用UDP传送1kb以下的数据。

1.4 理解物理传输和以太网
TCP有一个优点就是可以在不同的物理网络硬件之间传送数据。
以太网是当今应用最广泛的物理传输类型,很多不同的协议都要以运行在以太网上。
一个通过TCP/IP连接以太网的计算机有一个和网络接口相关的IP地址,它与一个本网络机器通信时,只需直接向该计算机发送信息即可,如果要和网外的机器通信,就必须把信息发送到本地网络的路由器,然后由路由器决定信息发送到哪里。
1.5 Python网络编程
当用Python来编写网络程序时,你会发现大致有两种情况:有些程序可以利用Python中已经有的协议模块(如HTTP或FTP)来写,有些程序则需要你自己写协议。
1.5.1底层接口
Python提供了访问底层操作系统Socket接口的全部方法,需要的时候这些接口可以为你提供灵活而强有力的功能。它还提供一些用于加密和认证通信的服务,如SSL/TLS.
1.5.1.1基本客户端操作
gopherclient.py
#!/usr/bin/python
import socket,sys

port = 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)

#./ gopherclient.py gopher.quux.org /

该程序实现的是Gopher协议,一种Web出现之前在Internet上非常流行的协议。
1.5.1.2错误和异常
Python会自动替你检查异常,并在有错误发生时产生异常,尝试给出一个不存在的主机名,如
./gopherclient.py nonexistant.example.com /
Traceback (most recent call last):
  File "./gopherclient.py", line 8, in ?
    s.connect((host,port))
socket.gaierror: (-2, 'Name or service not known')
Python会检测到错误并产生一个socket.gaierror异常。
可以稍微修改一个程序,让它出错信息更友好一些。
gopherclient2.py
#!/usr/bin/python
import socket,sys

host = sys.argv[1]
filename = sys.argv[2]
port = 70

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
  s.connect((host,port))
except socket.gaierror,e:
  print "Error connecting to server %s" % e
  sys.exit(1)

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

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

./gopherclient2.py nonexistant.example.com /
现在如果试图连接一个不存在的服务,程序将终止,你将得到一个友好的错误信息。
1.5.1.3文件类对象
Python库支持文件和文件类对象,Socket对象不提供类似接口,然而Python提供了一个makefile函数来生成你使用的文件类对象。
gopherclient3.py
#!/usr/bin/python
import socket,sys

host = sys.argv[1]
filename = sys.argv[2]
port = 70

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))
s.sendall(filename+"\r\n")
fd = s.makefile('rw',0)
for line in fd.readlines():
sys.stdout.write(line)

makefile函数,有两个可选参数:操作文件的模式和缓存的模式,操作文件类的模式表明你是只读、只写或者既读又写,缓存主要用于磁盘文件,对于交互式网络程序,它可能会阻碍程序的运行。
1.5.1.4 基本服务器操作
server.py 从客户端读一个字符串,显示一个应答,最后关闭客户端socket
#!/usr/bin/python
import socket

host = ''
port = 51234

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

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 %s"+line)
clientfile.close()
clientsocket.close()

调用socket.socket()创建socket
bind()绑定一个端口
调用listen()函数,开始等候客户端连接,设定每次最多等待处理的连接
主循环调用accept(),返回一个新的客户端socket和客户端的IP地址、端口号
1.5.2 高级接口
Python 提供很多协议模块,使你不需要编写太底层的网络程序,它可以很大程度上简化你的编程任务。
httplib:提供解析HTTP header功能。
gopherlibclient.py
#!/usr/bin/python
import gopherlib,sys

host = sys.argv[1]
file = sys.argv[2]

f = gopherlib.send_selector(file,host)
for line in f.readlines():
sys.stdout.write(line)

gopherlib模块负责建立socket连接。
Python还提供更高级的模块,为了处理URL,Python提供的模块可以让你的代码和几种协议一起工作。

urlclient.py
#!/usr/bin/python

import urllib,sys
host = sys.argv[1]
file = sys.argv[2]

f = urllib.urlopen('gopher://%s%s'%(host,file))
for line in f.readlines():
sys.stdout.write(line)
download.py
#!/usr/bin/python
import urllib,sys

f = urllib.urlopen(sys.argv[1])
while 1:
buf = f.read(2048)
if not len(buf):
   break
sys.stdout.write(buf)
./download.py http://http.us.debian.org/debian/ls-lR.gz |gunzip |more
1.6 总结
TCP/IP 协议可以用于多种不同网络传输,如modems连接的网络和以太网,每一个终端靠唯一的IP地址和端口号来区分。
服务器通过一些事先知道的端口号来侦听,当一个客户连接时,它的操作系统通常会选择一个事先不知道的端口号。
有两种常用的数据传输协议,TCP:提供高可靠性和完整的会话,UDP:用于小且简短但是快速的会话。
大多数人用Python编写网络程序,要么自己设计协议,要么用一些内置的模块来实现一些已经存在的协议。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值