python3网络编程:socket的简单使用

01.套接字

套接字用于应用程序间的通信,任何程序间的通信开始之前都要创建套接字
有两种类型的套接字:基于文件的和面向网络的。
套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个进程和另一个进程进行通信,也就是进程间通信(IPC Inter Process Communication)。
文件套接字:
Unix套接字是套接字的第一个家族,家族名AF_UNIX(又名AF_LOCAL),家族名代表地址家族(address family)
网络套接字:
网络套接字也有自己的家族名,AF_INET,另一个地址家族AF_INET6是用于ipv6寻址。还有一些其他的地址家族,但是目前使用最广泛的是AF_INET

python支持AF_UNIX.AF_NETLINK,AF_TIPC,AF_INET几个家族。对于网络编程来说,我们将使用AF_INET.所以接下来讨论的内容都是AF_INET家族的套接字
套接字地址有主机号(ip)和端口号两个部分组成,有效端口号的范围是0~65535,小于1024的端口号是系统预留的,所以我们写程序的时候不要去占用。

02.面向连接的套接字和无连接的套接字

001.面向连接的套接字

面向连接的通信提供序列化的、可靠的和不重复的数据交付,没有记录边界。每条消息可以拆成多个片段,并且每一个消息片段都能确保到达目的地,然后将他们按顺序组合在一起,最后将完整消息传递给正在等待的应用程序。
主要就是传输控制协议tcp。
为了创建tcp套接字,必须使用SOCK_STREAM作为套接字类型。

002.无连接的套接字

不需要建立连接,也无法确保数据的顺序性,可靠性和重复性。
可以类比于邮政服务,信件和包裹也许并不能以发送顺序到达,也可能根本没有到达。
相对于面向连接服务,没有创建维持连接需要的成本,资源消耗更小,更快速。
主要是用户数据报协议UDP
为了创建UDP协议的套接字,必须使用SOCK_DGRAM作为套接字类型。

tcp和udp都是结合ip协议寻找互联网上的主机。所以这种系统被称为TCP/IP,UDP/IP

03.python 中的网络编程

socket.socket(socket_family,socket_type,protocol=0)
socket_family是AF_UNIX或AF_INET,socket_type是SOCK_STREAM或SOCK_DGRAM。protocol通常省略,默认为0.
socket对象的其他方法接下来将通过实例来演示:

下面首先演示的是一个tcp时间戳服务器:

import socket
import time
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)

# 创建服务端套接字用于接受客户端的连接
tcpSerSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定本地端口
tcpSerSock.bind(ADDR)
# 设定允许连接的最大数值
tcpSerSock.listen(5)

while True:
    print('waiting for connection,local address:',ADDR)
#     accept方法接受客户端发送的请求,并且产生一个服务客户端用的socket,返回客户端的地址
    tcpClientSock,addr = tcpSerSock.accept()
    print('...connected from:',addr)
    while True:
#         建立连接后,用tcpClientSock服务客户端,接受客户端发送的数据,使用指定大小的缓冲区
        data = tcpClientSock.recv(BUFSIZE)
        print('recieving data:',data)
#     当没有收到数据时退出循环
        if not data:
            break
#         在客户端发送的数据前加上时间戳再送回,socket需要放送bytes类型的数据,所以这里b是转化二进制数据
        tcpClientSock.send(b'[%s] %s'%(bytes(time.ctime(),'utf-8'),data))
#     关闭服务客户端的socket
    tcpClientSock.close()
    
# 关闭服务器的socket,现实情况下服务器都是一直运行的,所以一般不会关闭
tcpSerSock.close()




接下来是创建tcp客户端
创建客户端比服务器简单一些,
下面创建的客户端连接之前创建的服务器,向服务器发送数据,并且打印服务器返回的数据。


import socket
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)

tcpCliSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)

while True:
    data = input('> ')
    if not data:
        break
#     socket需要放送bytes类型的数据,所以这里encode是转化二进制数据
    tcpCliSock.send(data.encode('utf8'))
    data = tcpCliSock.recv(BUFSIZE)
    if not data:
        break
    print(data)
tcpCliSock.close()
          

接下来是创建udp服务器。由于是无连接的,所以并没有为了成功而使一个客户端连接到一个独立的套接字的“转换”操作。

import socket
import time

HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)

udpSerSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udpSerSock.bind(ADDR)

while True:
    print('waiting for message...')
    data,addr = udpSerSock.recvfrom(BUFSIZE)
    print('receiving data from %s,data:%s'%(addr,data))
    sendstr='[%s] %s'%(time.ctime(),data)
    udpSerSock.sendto(sendstr.encode('utf8'),addr)
    print('...received from and returned to:',addr)
                      
udpSerSock.close()
# 创建udp客户端
import socket
import time

HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)

udpCliSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    data = input('>')
    if not data:
        break
    udpCliSock.sendto(data.encode('utf8'),ADDR)
    data,addr = udpCliSock.recvfrom(BUFSIZE)
    if not data:
        break
    print(data)
                    
udpCliSock.close()

04.socketserver模块

socketserver是python标准库里面的一个高级模块,目标是简化创建客户端和服务器的代码。

下面我们先介绍tcp时间戳服务器的例子:

import socketserver
import time

HOST = ''
PORT = 21567
ADDR = (HOST,PORT)


class MyRequestHandler(socketserver.StreamRequestHandler):
    def handle(self):
        print('...connected from:',self.client_address)
        self.wfile.write(('[%s] %s'%(time.ctime(),self.rfile.readline())).encode('utf8'))


tcpServ = socketserver.TCPServer(ADDR,MyRequestHandler)
print('waiting for connection...')
tcpServ.serve_forever()

客户端

import socket
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024 
ADDR = (HOST,PORT)

while True:
    tcpCliSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data = input('> ')
    if not data:
        break
    tcpCliSock.send(('%s\r\n'%data).encode('utf8'))
    data = tcpCliSock.recv(BUFSIZE)
    if not data:
        break
    print(data.strip())
    tcpCliSock.close()

用这个高级模块,自己带一些异常处理,可以检测到键盘中断了。

你可能感兴趣的:(python3网络编程:socket的简单使用)