Python学习之Socket通信的实现

一、Socket通信简介

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

这里推荐一篇大神的博客,这里讲socket通信讲的明明白白Socket通信原理,因为主要讲解底层原理,因此没有学过C或对底层了解不够多的看着有点吃力,我会根据大神的介绍对Python中封装的socket模块中的socket类的一些bind(),listen(),connent(),accept(),close()函数做介绍,这几个函数是我们通过python学习socket()通信的关键。

二、代码实现

服务端实现

import socket

#1、创建服务端的socket对象
server_socket = socket.socket()

#2、绑定一个ip和端口
server_socket.bind(('192.168.0.9',9091))

#3、服务器端一直监听是否有客户端进行连接
print('server_socket is listening 9091')
server_socket.listen()

#4、如果有客户端进行连接、则接受客户端的连接
clientSockt,addr =  server_socket.accept()   #返回客户端socket通信对象和客户端的ip

#5、客户端与服务端进行通信
data = clientSockt.recv(1024).decode('utf-8')
print('服务端收到客户端发来的消息:%s'%(data))

#6、服务端给客户端回消息
clientSockt.send(b'I am a server')

#7、关闭socket对象
clientSockt.close()    #客户端对象
server_socket.close()  #服务端对象

客户端实现

import socket
#1、创建socket通信对象
clientSocket = socket.socket()

#2、使用正确的ip和端口去链接服务器
clientSocket.connect(('192.168.0.9',9091))

#3、客户端与服务器端进行通信
    # 给socket服务器发送信息
clientSocket.send(b'I am a client')

    # 接收服务器的响应(服务器回复的消息)
recvData = clientSocket.recv(1024).decode('utf-8')
print('客户端收到服务器回复的消息:%s'%(recvData))

#4、关闭socket对象
clientSocket.close()

代码分析:

socket.cocket()函数用于创建socket对象其源代码如下:

    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
        # For user code address family and type values are IntEnum members, but
        # for the underlying _socket.socket they're just integers. The
        # constructor of _socket.socket converts the given argument to an
        # integer automatically.
        _socket.socket.__init__(self, family, type, proto, fileno)
        self._io_refs = 0
        self._closed = False

这里面有三个非常重要的参数,family,type,proto;

family:即协议域,又称协议族,常用的有AF_INET、AF_INET6、AF_LOCAL(又称AF_UNIX)、AF_ROUTE等等。协议族决定了socket()的地址类型,在通信中必须采用对应的地址,AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

type:指socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。

proto:是指定协议常用的协议有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

注意:并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。

通常我们使用下面几种:

family:

         socket.AF_INET:指定通过IPV4进行连接

         socket.AF_INET6:指定通过IPV6进行通信

type  :
                    socket.SOCK_STREAM:通过TCP进行通信

         socket.SOCK_DGRAM: 通过udp进行通信

bind()

socket.bind()函数把一个地址族中的特定地址赋给socket,例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket对象

源码:

    def bind(self, address): # real signature unknown; restored from __doc__
        """
        bind(address)
        
        Bind the socket to a local address.  For IP sockets, the address is a
        pair (host, port); the host must refer to the local host. For raw packet
        sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])
        """
        pass

listen()

listen()函数,当服务器在调用socket()、bind()之后就会调用listen()函数来监听其绑定ip和端口,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

源码

    def listen(self, backlog=None): # real signature unknown; restored from __doc__
        """
        listen([backlog])
        
        Enable a server to accept connections.  If backlog is specified, it must be
        at least 0 (if it is lower, it is set to 0); it specifies the number of
        unaccepted connections that the system will allow before refusing new
        connections. If not specified, a default reasonable value is chosen.
        """
        pass

这里参数backlog是指socket可以排队的最大连接个数。

accept()

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。

三、使用UDP协议进行socket通信

代码:

服务端

import socket

serverSocket = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
# socket.AF_INET:指定通过IPV4进行连接
# socket.SOCK_DGRAM: 通过udp进行通信
serverSocket.bind(('192.168.0.9',9997))
# 使用UDP协议进行socket通信,服务器不需要进行监听
while True:
    data , addr = serverSocket.recvfrom(1024)
    print('接收到客户端的信息:',data)
    print('客户端的地址为:',addr)
    recvdata = input('server >>').encode('utf-8')
    serverSocket.sendto(recvdata,addr)

客户端

import socket
clientSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
    msg = input('client >>:')
    msg = msg.encode()
    clientSocket.sendto(msg,('192.168.0.9',9997))
    print('接收到客户端的消息为:',clientSocket.recv(1024))

四、练习:

我们在linux中使用ssh服务的时候就是用了socket通信,在这个我们简单实现这个功能(只有部分命令功能可以实现)

服务端

import socket
import os
import time
#1.如何创建socket:
# family:
#       socket.AF_INET:指定通过IPV4进行连接
#       socket.AF_INET6:指定通过IPV6进行通信
# type  :
#       socket.SOCK_STREAM:通过TCP进行通信
#       socket.SOCK_DGRAM: 通过udp进行通信

with socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) as serverScoket:
    serverScoket.bind(('192.168.0.9',9999))
    serverScoket.listen()
    clientSocket , addr = serverScoket.accept()
    with clientSocket:
        while True:
            time.sleep(1)
            cmd = clientSocket.recv(1024).decode('utf-8')
            print(cmd)
            res = os.popen(cmd).read().encode('utf-8')
            if res:
                clientSocket.send(res)

客户端

import socket
#1、创建socket通信对象
clientSocket = socket.socket()

#2、使用正确的ip和端口去链接服务器
clientSocket.connect(('192.168.0.9',9091))

#3、客户端与服务器端进行通信
    # 给socket服务器发送信息
clientSocket.send(b'I am a client')

    # 接收服务器的响应(服务器回复的消息)
recvData = clientSocket.recv(1024).decode('utf-8')
print('客户端收到服务器回复的消息:%s'%(recvData))

#4、关闭socket对象
clientSocket.close()

猜你喜欢

转载自blog.csdn.net/m0_37717595/article/details/81101895