1 什么是Socket
在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。
我的理解就是Socket就是该模式的一个实现:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
2 socket服务器端代码及其解释
importsocket
HOST= '127.0.0.1'PORT= 8888server=socket.socket()
server.bind((HOST, PORT))
server.listen(1)print(f'the server is listening at {HOST}:{PORT}')print('waiting for conntection...')
conn, addr=server.accept()print(f'connect success addr={addr}')print('waiting for message')whileTrue:
msg= conn.recv(1024)print('the clint send:', msg.decode())
response= input('enter your response:')
conn.send(response.encode())print('waiting for answer')
分析该程序:
首先,sever为一个实例化的socket套接字,随后server绑定到本地地址,以用户名:端口号的方式给出。随后对该端口进行监听。
一旦收到回复,会以元组的形式返回一个连接对象conn与地址addr。这里注意到addr地址以元组(IPaddr,port)的形式给出。随后就可以利用conn进行通信了
3 socket客户端代码及其解释
importsocketimportsystry:
host, port= input('enter host address like host:port:').split(':')exceptValueError:print('the address is wrong')
sys.exit(-1)if len(host) == 0 or len(port) ==0:print('the address is wrong')
sys.exit(-1)else:
client=socket.create_connection((host, port))print('connect successfully. waiting for response...')
client.send(b'hello server.')whileTrue:
response= client.recv(1024)print('the response is:', response.decode())
msg= input('please enter a answer:')
client.send(msg.encode())print('waiting for response...')
首先,请用户输入地址,端口号,之后以“:”为间隔分开。如果输入出错则抛出ValueError。如果是正确的地址则创建连接。
随后在连接中进行通信。
结果大概如下图所示:
server端:
client端:
可以看见能够成功运行
4 相关API及分析:
Python下我们重点分析socket接口对象。
在socket.pyi中,我们找到如下的socket类及方法定义:
classsocket:
family: int
type: int
proto: intif sys.version_info < (3,):def __init__(self, family: int = ..., type: int =...,
proto: int= ...) ->None: ...else:def __init__(self, family: int = ..., type: int =...,
proto: int= ..., fileno: Optional[int] = ...) ->None: ...if sys.version_info >= (3, 2):def __enter__(self: _SelfT) ->_SelfT: ...def __exit__(self, *args: Any) ->None: ...#--- methods ---
#second tuple item is an address
def accept(self) ->Tuple[socket, Any]: ...def bind(self, address: Union[tuple, str, bytes]) ->None: ...def close(self) ->None: ...def connect(self, address: Union[tuple, str, bytes]) ->None: ...def connect_ex(self, address: Union[tuple, str, bytes]) ->int: ...def detach(self) ->int: ...def fileno(self) -> int: ...
该类中详细定义了对于网络接口的使用规范。我们重点查看connect函数,其定义如下:
defconnect(self, addr):"""Connects to remote ADDR, and then wraps the connection in
an SSL channel."""self._real_connect(addr, False)
这里提供SSL加密的安全连接,我们继续查看_real_connect()内置方法:
def_real_connect(self, addr, connect_ex):ifself.server_side:raise ValueError("can't connect in server-side mode")#Here we assume that the socket is client-side, and not
#connected at the time of the call. We connect it, then wrap it.
ifself._connected:raise ValueError("attempt to connect already-connected SSLSocket!")
sslobj=self.context._wrap_socket(self, False, self.server_hostname)
self._sslobj= SSLObject(sslobj, owner=self,
session=self._session)try:ifconnect_ex:
rc=socket.connect_ex(self, addr)else:
rc=None
socket.connect(self, addr)if notrc:
self._connected=Trueifself.do_handshake_on_connect:
self.do_handshake()returnrcexcept(OSError, ValueError):
self._sslobj=Noneraise
同函数中注释所说明的,该函数假设自己处在客户端并且没有对于目标地址的连接。该函数目的为连接到指定地址并调用相关的SSL对象对该链接进行封装。
5 Linux Socket API
因为在Python语言中,实现我上述程序的网络端口也是socket套接字,其内置方法与Linux Socket较为相似,包括bind()、 connect()等方法,差别仅仅在于实现这些函数的语言不同。
在逻辑与功能设计层面,两者思想是相似甚至相同的。