欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

socket

程序员文章站 2022-04-24 11:37:48
...

原始实现VS框架实现

“掌握一个类似于框架的高级工具是有用的,但是基础的东西可以让你永远不被淘汰。不要被工具限制了自己的发展。 ”在当今Python服务器框架 (framework, 比如Django, Twisted, web.py等等) 横行的时代,从底层的socket开始写服务器似乎是一个出力不讨好的笨方法。

框架的意义在于掩盖底层的细节,提供一套对于开发人员更加友好的API,并处理诸如MVC的布局问题。框架允许我们快速的构建一个成型而且成熟的Python服务器。然而,框架本身也是依赖于底层(比如socket)。对于底层socket的了解,不仅可以帮助我们更好的使用框架,更可以让我们明白框架是如何设计的。

更进一步, ”如果拥有良好的底层socket编程知识和其他系统编程知识,你完全可以设计并开发一款自己的框架。如果你可以从底层socket开始,实现一个完整的Python服务器,支持用户层的协议,并处理好诸如MVC(Model-View-Control)、多线程(threading)等问题,并整理出一套清晰的函数或者类,作为接口(API)呈现给用户,你就相当于设计了一个框架。“

我们已经看到:

许多成功的网站都是利用动态语言(比如Python, Ruby或者PHP,比如twitter和facebook)快速开发,在网站成功之后,将代码转换成诸如C和JAVA这样一些效率比较高的语言,从而让服务器能更有效率的面对每天亿万次的请求。在这样一些时间,底层的重要性,就远远超过了框架。

预备知识:TCP/IP和socket

我们需要对网络传输,特别是TCP/IP协议和socket有一定的了解。socket是进程间通信的一种方法 (参考Linux进程间通信),它是基于网络传输协议的上层接口。socket有许多种类型,比如基于TCP协议或者UDP协议(两种网络传输协议)。其中又以TCP socket最为常用。

socket接口是实际上是操作系统提供的系统调用。 TCP socket与双向管道(duplex PIPE)有些类似,一个进程向socket的一端写入或读取文本流,而另一个进程可以从socket的另一端读取或写入,比较特别是,这两个建立socket通信的进程可以分别属于两台不同的计算机。

所谓的TCP协议,就是规定了一些通信的守则,以便在网络环境下能够有效实现上述进程间通信过程。双向管道(duplex PIPE)存活于同一台电脑中,所以不必区分两个进程的所在计算机的地址,而socket必须包含有地址信息,以便实现网络通信。

一个socket包含四个地址信息: 两台计算机的IP地址和两个进程所使用的端口(port)。IP地址用于定位计算机,而port用于定位进程 (一台计算机上可以有多个进程分别使用不同的端口)。

TCP socket

在互联网上,我们可以让某台计算机作为服务器。服务器开放自己的端口,被动等待其他计算机连接。当其他计算机作为客户,主动使用socket连接到服务器的时候,服务器就开始为客户提供服务。 请求新浪网页

# 导入socket模块
import  socket

# 创建一个客户端socket
# 参数1: 使用 socket.AF_INET 表示使用的ip协议 版本,socket.AF_INET 是ipv4, socket.AF_INET6 表示的是ipv6
# 参数2: SOCK_STREAM 表示数据以流的形式传输
clientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 连接服务器--打招呼
# 参数address是服务器地址, 该地址包括ip地址,端口号  ,参数是元组的形式,第一个是IP地址. 第二是端口号
# http://www.sina.com.cn/ 域名 ------> DNS域名服务器 ---->ip地址
clientSocket.connect(("www.baidu.com.cn",80))


# 发起请求,请求新浪
# 需要字节形式的数据
clientSocket.send(b"GET / HTTP/1.1\r\nHost:www.baidu.com.cn\r\n\r\n")

# 创建一个list来接收所有的数据
listData = []

# 将数据写入到文件中去
# wf = open("sina.html","wb")



# 接收数据,参数表示接受的数据大小
while True:
    content = clientSocket.recv(1024)
    if len(content) == 0: #  接收完毕
        break
    listData.append(content)
    # wf.write(content)
    # wf.flush()

# 字节转换成字符串
strData = b"".join(listData).decode("utf-8")
# print(strData)
# wf.close()

# 关闭连接
clientSocket.close()

# 将响应头 与 html内容分开, 参数2表示只分割一次
head,htmlbody = strData.split("\r\n\r\n",1)
# print(head)
print(htmlbody)
复制代码

首先是服务器端: 我们使用bind()方法来赋予socket以固定的地址和端口,并使用listen()方法来被动的监听该端口。当有客户尝试用connect()方法连接的时候,服务器使用accept()接受连接,从而建立一个连接的socket:

import socket

# Address
HOST = ''
PORT = 8000

reply = 'Yes'

# 创建套接字,绑定套接字到本地IP与端口
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
# passively wait, 3: maximum number of connections in the queue
s.listen(3)

# accept and establish connectionconn, 
addr = s.accept()

# receive message
request = conn.recv(1024)
print 'request is: ',request
print 'Connected by', addr

# send message
conn.sendall(reply)

# close connection
conn.close()
复制代码

将以上保存为文件org_ser.py

其次,客户端:我们主动使用connect()方法来搜索服务器端的IP地址和端口,以便客户可以找到服务器,并建立连接。

import socket

# Address
HOST = '172.20.202.155'
PORT = 8000

request = 'can you hear me?'

# configure socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

# send message
s.sendall(request)

# receive message
reply = s.recv(1024)
print 'reply is: ',reply

# close connection
s.close()
复制代码

调试运行:

左上角是用浏览器对服务器进行访问的结果,服务器回传了“Yes”,对应服务器中的代码:reply = 'Yes'。

中间图是服务器运行图,最下面是客户端运行图,可以看出客户端向服务器请求的内容为:request = 'can you hear me?',而客户端得到的反馈是“Yes”。

程序运行正常

作者:rebirth_2017 链接:www.jianshu.com/p/a324616b8… 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。