#! /usr/bin/env python3

# -*- coding:utf-8 -*-

#TCP/IP简介

#为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现互联网这个目标,互联网协议簇(Internet Protocol Suite)就是

#通用协议标准。Internet 是由inter 和net 两个单词组合起来的,原意就是连接’网络‘的网络,有了Internet,任何私有网络,只要支持这个协议,就可以联入互联网。

#虽然互联网协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称TCP/IP协议。

#通信的时候,双方必须知道对方的标识,好比发邮件必须知道对方的邮件地址。互联网上每个计算机的唯一标识就是IP地址,类似123.123.123.123

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

#IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有

#多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途经多个路由,但不保证能到达,也不保证顺序到达。

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

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

#TCP协议则是建立在IP协议上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保

#对方按顺序收到,如果包丢掉了,就自动重发。

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

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

#端口有什么作用?在两天计算机通信时,只发IP地址不够,因为同一台计算机上跑着多个网络程序。一个IP包来了后,到底是交给浏览器还是QQ,就需要端口号来区分。

#每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。

#一个进程也可能同时与多个计算机建立链接,因此它会申请很多端口。

#TCP编程

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

#即可。

#客户端

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

#举个例子,当我们在浏览器中访问新浪时,我们自己的计算机就是客户端,浏览器会主动向新浪的服务器发起连接。如果一切顺利,新浪的服务器接受了我们的连接,

#一个TCP连接就建立起来了,后面的通信就是发送网页内容了。

#导入socket库

import socket

#创建一个socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#建立连接:

s.connect(('www.sina.com.cn',80))  #参数是一个tuple,包含地址和端口号。

#创建Socket时,AF_INET指定使用IPV4协议,如果要用更先进的IPV6,就指定为AF_INET6 。 SOCK_STREAM指定使用面向流的TCP协议,这样,一个Socket对象就创建

#成功,但是还没有建立连接。

#客户端要主动发起TCP连接,必须知道服务器的IP地址和端口号。新浪网站的IP地址可以用域名www.sina.com.cn自动转换到IP地址,但是怎么知道新浪服务器的端口呢?

#答案是作为服务器,提供什么样的服务,端口号就必须固定下来。由于我们想要访问网页,因此新浪提供网页服务的服务器必须把端口号固定在80端口,因为80端口

#是web服务的标准端口。其他服务都有对应的标准端口号,例如SMTP服务是25端口,FTP服务是21端口,等等。端口号小于1024的是internet标准服务的端口,端口号

#大于1024的,可以任意使用。

#建立TCP连接后,我们就可以向新浪服务器发送请求,要求返回首页内容:

#发送数据:

s.send(b'GET / HTTP/1.1\r\nHost:www.sina.com.cn\r\nConnection: close\r\n\r\n')

#TCP连接创建的是双向通道,双方都可以同时给对方发数据。但是谁先发谁后发,怎么协调,要根据具体的协议来决定。例如,Http协议规定客户端必须先发请求给

#服务器,服务器收到后才发数据给客户端。

#发送的文本格式必须符合Http标准,如果格式没问题,接下来就可以接收新浪服务器返回的数据了:

#接收数据

buffer=[]

while True:

#每次最多接收1k字节:

d=s.recv(1024)

if d:

buffer.append(d)

else:

break

data=b''.join(buffer)

#接收数据时,调用recv(max)方法,一次最多接收指定的字节数,因此,在一个while循环中反复接收,直到recv()返回空数据,表示接收完毕,退出循环。

#当我们接收完数据后,调用close()方法关闭Socket,这样,一次完整的网络通信就结束了:

#关闭连接:

s.close()

#接收到的数据包括HTTP头和网页本身,我们只需要把HTTP头和网页分离一下,把HTTP头打印出来,网页内容保存到文件:

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文件,就可以看到新浪的首页了。

#服务器

#和客户端编程相比,服务器编程就要复杂一些。

#服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Soket连接了。

#所以,服务器会打开固定端口(比如80)监听,每来一个客户端连接,就创建该Socket连接。由于服务器会有大量来自客户端的连接,所以,服务器要能够区分一个

#Socket连接是和哪个客户端绑定的。一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket.

#但是服务器还需要同时响应多个客户端的请求,所以,每个连接都需要一个新的进程或者新的线程来处理,否则,服务器一次就只能服务一个客户端了。

#我们来编写一个简单的服务器程序,它接收客户端连接,把客户端发过来的字符串加上Hello再发回去。

#创建一个基于IPV4和TCP协议的Socket:

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#然后我们要绑定监听的地址和端口。服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1

#绑定本机地址。127.0.0.1是一个特殊的IP地址,表示本机地址,如果绑定到这个地址,客户端必须同时在本机运行才能连接,也就是说,外部计算机无法连接进来。

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

#监听端口:

s.bind(('127.0.0.1',9999))

#紧接着,调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量:

s.listen(5)

print('Waiting for connection...')

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

while True:

#接收一个新连接:

sock,addr=s.accept()

#创建新线程来处理TCP连接:

t=threading.Thread(target=tcplink,args=(sock,addr))

t.start()

#每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接收其他客户端的连接:

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)

#连接建立后,服务器首先发一条欢迎消息,然后等待客户端数据,并加上Hello再发送给客户端。如果客户端发送了exit字符串,就直接关闭连接。

#要测试这个服务器程序,我们还需要编写一个客户端程序:

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()

#我们需要打开两个命令行窗口,一个运行服务器程序,另一个运行客户端程序,就可以看到效果了:

#需要注意的是,客户端程序运行完毕就退出了,而服务器程序会永远运行下去,必须按Ctrl+C退出程序。

#用TCP协议进行Socket编程在Python中十分简单,对于客户端,要主动连接服务器的IP和指定端口,对于服务器,要首先监听指定端口,然后对每一个新的连接,

#创建一个线程或进程来处理。通常,服务器程序会无限运行下去。

#同一个端口,被一个Socket绑定后,就不能被别的Socket绑定了。

TCP/IP协议 计算机间的通讯,传输、socket 传输通道的更多相关文章

  1. TCP/IP协议(5):传输层之TCP

    一.TCP报文 上图为TCP报文的格式,可以看到TCP头部占20个字节,其中红色圆圈中每一项占一位,表示TCP报文的类型,置1表示该项有效. SYN表示建立连接.    FIN表示关闭连接.    A ...

  2. TCP/IP协议(6):传输层之UDP

    一. UDP用户数据报协议,它是一个无连接的,面向数据报的协议,它不提供可靠性但传输速度比TCP要快. UDP数据报中的“UDP长度”为两个字节,所以我们要发送的UDP数据最多支持65507大约68K ...

  3. Python之路(第三十篇) 网络编程:socket、tcp/ip协议

    一.客户端/服务器架构 1.硬件C/S架构(打印机) 打印机作为一个服务端,电脑连接打印机进行打印 2.软件C/S架构 互联网中处处是C/S架构 如谷歌网站是服务端,你的浏览器是客户端(B/S架构也是 ...

  4. TCP/IP协议原理与应用笔记07:HTTP、TCP/IP与socket区别

    1. TCP/IP协议与HTTP协议区别:      HTTP 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件 ...

  5. 简单理解TCP/IP协议

    一.什么是TCP/IP TCP/IP是一个协议族,是因为TCP/IP协议包括TCP.IP.UDP.ICMP.RIP.TELNETFTP.SMTP.ARP.TFTP等许多协议,这些协议一起称为TCP/I ...

  6. 门面模式的典型应用 Socket 和 Http(post,get)、TCP/IP 协议的关系总结

    门面模式的一个典型应用:Socket 套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息: 连接使用的 ...

  7. http、TCP/IP协议与socket之间的区别

    http.TCP/IP协议与socket之间的区别     网络由下往上分为:  www.2cto.com   物理层--                       数据链路层-- 网络层--   ...

  8. http、TCP/IP协议与socket之间的区别(转载)

    http.TCP/IP协议与socket之间的区别  https://www.cnblogs.com/iOS-mt/p/4264675.html http.TCP/IP协议与socket之间的区别   ...

  9. 套接字、UDP通信、TCP通信、TCP/IP协议簇

    一.套接字(socket) 1.英语单词socket:n.插座:穴:v.插入插座 2.套接字就是源IP地址和目的IP地址.源端口号和目的端口号的组合,是通过传输层进行通信的.IP指定电脑,端口指定某一 ...

随机推荐

  1. iframe和ajax文件上传方法

    为什么使用这两种方法文件上传呢,主要是因为局部刷新问题 上传问题,主要是使用form表单,或者用请求一个文件上传 iframe 大多网站都是有一个整体的固定结构,然后进行局部刷新,我们可以使用AJAX ...

  2. Python全栈开发-有趣的小程序

    进度条的打印 import sys,time for i in range(20): sys.stdout.write('$')      #stdout是标准输出的意思,在一般电脑上,stdout的 ...

  3. 第 3 章 镜像 - 021 - Docker 镜像小结

    镜像小结 镜像的常用操作子命令: images    显示镜像列表 history   显示镜像构建历史 commit    从容器创建新镜像 build     从 Dockerfile 构建镜像 ...

  4. 第 3 章 镜像 - 020 - 搭建本地 Registry

    Docker Hub 虽然非常方便,但还是有些限制,比如: 需要 internet 连接,而且下载和上传速度慢. 上传到 Docker Hub 的镜像任何人都能够访问,虽然可以用私有 reposito ...

  5. Getting Started with Processing 第十章——对象

    不像原始数据类型boolean,int 和 float 只能存一个值,一个对象可以存很多值.但这也是我们讲的一部分,对象也是用相关函数将变量编组的一种方式. 域和方法 在对象的上下文中,一个变量被叫做 ...

  6. validateRequest 相关的作用

    在 Web 应用程序中,要阻止依赖于恶意输入字符串的黑客攻击,约束和验证用户输入是必不可少的.跨站点脚本攻击就是此类攻击的一个示例.其他类型的恶意数据或不需 要的数据可以通过各种形式的输入在请求中传入 ...

  7. 【转】 详解C中volatile关键字

    转自: http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html volatile提醒编译器它后面所定义的变量随时都有可能 ...

  8. 文献导读 - Machine Learning Identifies Stemness Features Associated with Oncogenic Dedifferentiation

    参考: Machine Learning Identifies Stemness Features Associated with Oncogenic Dedifferentiation 前所未有!1 ...

  9. 20171024xlVBA批量获取PPT\WORD\PDF页数

    Public Sub ModifyFileNames() Dim FolderPath As String Dim FileNames As Variant Dim dotPos As Long Di ...

  10. php单例模式的使用场景,使用方法

    一个类只有一个对象实例 1.含义 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 2 ...