Socket 介绍
Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。
Socket是操作系统提供的一个编程接口,并不一定需要TCP/IP网络
在socket里面有一个families的概念,简单介绍下几个常见的families
- socket.AF_INET # IPv4
- socket.AF_INET6 # IPv6
- socket.AF_UNIX # unix domain socket(本地套接字)
除了上面的三个还有很多的families,但是其他的不是常用到
名词解释:套接字,就是源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务。
它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
socket常用的传输方式
- socket.SOCK_DGRAM # UDP
- socket.SOCK_STREAM # TCP
- socket.SOCK_RAW # 这种传输方式既不是TCP也不是UDP,它的传输需要用自己的用户空间封包
这是常见的三种传输方式,当然也还有其他的传输方式,但是很少用到
Socket TCP server/client
server
In [20]: import socket
In [21]: so = socket.socket() # 创建socket实例
In [22]: so.bind(('127.0.0.1', 8002)) # bind的参数格式是元组,并且因为不是特权端口,因此端口号必须是1024 ~ 65535之间的
In [23]: so.listen() # 监听端口,只有在端口监听以后server端才算启动
In [24]: s, info = so.accept() # 返回客户端实例及socket地址, accept是阻塞的,直到客户端建立连接,才会通过
In [25]: s.recv(1024) # accept返回的socket实例,可以接受数据,也是阻塞的
Out[25]: b'lanyulei\r\n'
In [27]: s.send(b'shuaige') # 向client 发送消息
Out[27]: 7
In [28]: s.close() # 关闭客户端连接,但是服务端没有关闭
client的情况
(lanyulei) [root@iz2zedc6tjfwomqmnq40vyz ~]# telnet 127.0.0.1 8002
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
lanyulei # 向服务端发送的数据
shuaige # 服务端发过来的数据
listen 需要一个文件描述符
每个连接也对应一个文件描述符,因此accept客户端连接是不能使用之前的
在socket中当客户端主动断开连接的时候, server端是无法确认的,server端会将自动断开的client保持一种close_wait的状态一直等到系统回收的时候才会释放
在socket编程中有一个makefile方法,这个方法需要慎用,makefile是生成类文件对象的,当socket实例close的时候,socket是没有真正关闭的,只有当makefile的类文件对象全部close了以后,才会真正的close
- so.getsockname() # 获取本地地址
- so.getpeername() # 获取对端地址,也就是客户端地址
socket聊天室服务器,server端
import socket
import threading
class ChatServer:
def __init__(self, ip='127.0.0.1', port=1234):
self.sock = socket.socket()
self.clients = {}
self.addr = (ip, port)
self.event = threading.Event()
def revc(self, so, ip, port):
while not self.event.is_set():
data = so.recv(1024).decode()
if data.strip() == '/quit':
so.close()
self.clients.pop((ip, port))
return
for s in self.clients.values():
s.send('{}:{}\t{}'.format(ip, port, data).encode())
def accept(self):
while not self.event.is_set():
so, (ip, port) = self.sock.accept()
self.clients[(ip, port)] = so
threading.Thread(target=self.revc, name='client-{}:{}'.format(ip, port), args=(so, ip, port)).start()
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
t = threading.Thread(target=self.accept, name='listen', daemon=True)
try:
t.start()
t.join()
except KeyboardInterrupt:
self.stop()
def stop(self):
for so in self.clients.values():
so.close()
self.sock.close()
self.event.set()
if __name__ == '__main__':
chatserver = ChatServer()
chatserver.start()
更多方法自行百度