1.  
  2. 主页
  3.  / 
  4. Python基础到高级
  5.  / 
  6. socket网络编程
  7.  / 
  8. server

server

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

更多方法自行百度

这篇文章对您有用吗?

我们要如何帮助您?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注