socket又称为套接字,它是所有网络通信的基础。网络通信其实就是进程间的通信,socket主要使用IP地址、协议、端口号来标识一个进程。端口号的范围为0~65535(用户端口号一般大于1024),协议有很多种,一般我们经常用到的就是TCP、UDP。

15.1 socket常用函数

socket.socket(socket_family,socket_type,protocol=0)   创建套接字

socket_family可以是如下参数:

socket.AF_INET: 使用IPv4协议。

socket.AF_INET6:使用IPv6协议。

socket.AF_UNIX: 只能够用于单一的Unix系统进程间通信。

socket_type可以是如下参数:

socket.SOCK_STREAM:流式socket , for TCP

socket.SOCK_DGRAM: 数据报式socket , for UDP

socket.SOCK_RAW:原始套接字。普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

socket.SOCK_RDM: 一种可靠的UDP形式,即保证交付数据报但不保证顺序。

socket.SOCK_SEQPACKET: 可靠的连续数据包服务。

protocol参数:0(默认)与特定的地址家族相关的协议。如果是0,则系统就会根据地址格式和套接类别,自动选择一个合适的协议。

服务器端套接字函数如下:

bind()
listen(backlog)
accept()

客户端socket函数如下:

connect(address)
connect_ex(address)

服务器端和客户端公共socket函数如下:

settimeout(timeout)
gettimeout()
recv(bufsize[,flag])
send(string[,flag])
sendall(string[,flag])
sendto(string[,flag],address)
recvfrom(bufsize[.flag])
close()
setsockopt(level,optname,value)

例:setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)   防止socket server重启后端口被占用。

getsockopt(level,optname[.buflen])
setblocking(flag)
getpeername()
getsockname()

15.2 创建TCP服务器端和客户端实例

TCP服务器端代码实例如下:

import socket
import threading
import time
import sys
def tcp_server():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 防止socket server重启后端口被占用(socket.error: [Errno 98] Address already in use)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('127.0.0.1', 6666))
        s.listen(10)
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print('Waiting connection...')
    while 1:
        conn, addr = s.accept()
        t = threading.Thread(target=deal_data, args=(conn, addr))
        t.start()
def deal_data(conn, addr):
    print('Accept new connection from {0}'.format(addr))
    conn.send(('Hi, Welcome to the server!').encode())
    while 1:
        data = conn.recv(1024)
        print('{0} client send data is {1}'.format(addr, data.decode()))
        if data.decode() == 'exit' or not data:
            print('{0} connection close'.format(addr))
            conn.send(bytes('Connection closed!', 'UTF-8'))
            break
        conn.send(bytes('Hello, {0}'.format(data), "UTF-8"))  # a bytes-like object is required, not 'str'
    conn.close()
if __name__ == '__main__':
    tcp_server()

TCP客户端代码实例如下:

import socket
import sys
def tcp_client():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', 6666))
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print(s.recv(1024))  # 目的在于接受:Accept new connection from (...
    while 1:
        data = input('please input work: ').encode()
        print(data)
        s.send(data)
        print('aa', s.recv(1024))
        if data.decode() == 'exit':
            break
    s.close()
if __name__ == '__main__':
    tcp_client()