-->

python网络编程之socket

2021-01-16 02:30发布

Python Socket模块学习之详解

###1.概述

  • socket套接字编程遵循客户-服务端架构;

  • python中的socket模块,是对套接字编程的实现,主要支持tcp、udp;

    • tcp是可靠的、面向连接的、尽力传输的协议;
    • udp是不可靠的、面向非连接的、不尽力传输的协议;
    • 不可靠不代表它没有用,udp有自己的应用场景,语音和视频几乎都在使用udp协议,它的不可靠只是相对于tcp来说的,但是它的好处就是效率,高效在某些场景要比可靠性重要;

###2.socket模块函数注解

  • 创建套件字:

    • s.socket() 根据地址族family、套件字类型socktype、使用的协议proto创建套件字
      • family: AF_INET (the default), AF_INET6 or AF_UNIX
      • socktype: SOCK_STREAM (the default, tcp), SOCK_DGRAM(udp)
      • proto: 默认为0, 一般不使用
  • 服务器端套接字方法:

    • socket.bind(address) 绑定地址到套接字对象,地址为主机、端口对
    • s.listen() 监听端口
    • s.accept() 被动的阻塞式的接受连接
  • 客户端套接字方法:

    • s.connect() 初始化连接
    • s.connect_ex() connect()的扩展版本,出错时会返回错误码而不是抛出异常
  • 共用套接字方法:

    • s.recv() 接收TCP数据
    • s.send() 发送TCP数据
    • s.sendall() 完整发送TCP数据
    • s.recvfrom() 接收UDP数据
    • s.sendto() 发送UDP数据
    • s.getpeername() 连接到当前套接字的远端的地址
    • s.getsockname() 当前套接字的地址
    • s.getsockopt() 返回指定套接字的参数
    • s.setsockopt() 设置指定套接字的参数
    • s.close() 关闭套接字
  • 阻塞式套接字方法:

    • s.setblocking() 设置套接字的阻塞与非阻塞模式
    • s.settimeout() 设置阻塞套接字操作的超时时间
    • s.gettimeout() 得到阻塞套接字操作的超时时间
  • 面向文件的套接字的方法

    • s.fileno() 套接字的文件描述符
    • s.makefile() 创建一个与该套接字关联的文件

更多详情参见socket模块的api文档

###3. 举例 服务端demo:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Echo server program
import socket
import sys

HOST = None     # Symbolic name meaning all available interfaces
PORT = 8888     # Arbitrary non-privileged port

def bind(host, port):
    s = None
    if host == "":
        host = None
    for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
                                  socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
        family, socktype, proto, canonname, sockaddr = res
        print (family, socktype, proto, canonname, sockaddr)
        try:
            s = socket.socket(family, socktype, proto)
        except socket.error as msg:
            s = None
            continue
        try:
            s.bind(sockaddr)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # s.setblocking(0)
            s.listen(128)
        except socket.error, e:
            print e
            s.close()
            s = None
            continue
        break
    return s


def main():
    s = bind("", PORT)
    if s is None:
        print 'could not open socket'
        sys.exit(1)
    while 1:
        conn, addr = s.accept()
        print u"客户端socket: %s" % conn
        print u"客户端socket地址: %s" % repr(addr)
        print u"客户端socket远端地址: %s" % repr(conn.getpeername())
        print u"客户端socket本端地址:%s" % repr(conn.getsockname())
        data = conn.recv(1024)
        if not data:
            break
        print u'收到的data: %s\n\n' % data
        conn.send(data)
    conn.close()

if __name__ == '__main__':
    main()

客户端demo:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Echo client program
import socket
import sys

HOST = None    # The remote host
PORT = 8888    # The same port as used by the server


def main():
    s = None
    for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
        family, socktype, proto, canonname, sockaddr = res
        try:
            s = socket.socket(family, socktype, proto)
        except socket.error as msg:
            s = None
            continue
        try:
            s.connect(sockaddr)
        except socket.error as msg:
            s.close()
            s = None
            continue
        break
    if s is None:
        print 'could not open socket'
        sys.exit(1)

    print u"客户端socket远端地址: %s" % repr(s.getpeername())
    print u"客户端socket本端地址:%s" % repr(s.getsockname())

    s.sendall('Hello, world')
    data = s.recv(1024)
    s.close()
    print u'从服务端接收到的data %s' % repr(data)

if __name__ == '__main__':
    main()

###4.注意事项

  • 设置socket实例对象端口可重用
    • s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
标签: