Python Socket 编程:基于TCP套接字

Python 提供了两个基本的 socket 模块:

  • Socket 它提供了标准的BSD Socket API。
  • SocketServer 它提供了服务器重心,可以简化网络服务器的开发。

Socket 类型

套接字格式:socket(family, type[,protocal])使用给定的套接族,套接字类型,协议编号(默认为0)来创建套接字
在这里插入图片描述

创建TCP Socket:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

服务器端 Socket 函数

Socket 函数描述
s.bind(address)将套接字绑定到地址,在AF_INET下,以tuple(host, port)的方式传入,如s.bind((host, port))
s.listen(backlog)开始监听TCP传入连接,backlog指定在拒绝链接前,操作系统可以挂起的最大连接数,该值最少为1,大部分应用程序设为5就够用了
s.accept()接受TCP链接并返回(conn, address),其中conn是新的套接字对象,可以用来接收和发送数据,address是链接客户端的地址。
    """accept() -> (socket object, address info)

    Wait for an incoming connection.  Return a new socket
    representing the connection, and the address of the client.
    For IP sockets, the address info is a pair (hostaddr, port).
    """
    fd, addr = self._accept()

客户端 Socket 函数

在这里插入图片描述

公共 Socket 函数

在这里插入图片描述
在这里插入图片描述

Socket 编程思想

TCP 服务器 1、创建套接字,绑定套接字到本地IP与端口

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind()

2、开始监听链接
s.listen()

3、进入循环,不断接受客户端的链接请求

While True:
    s.accept()

4、接收客户端传来的数据,并且发送给对方发送数据

s.recv()
s.sendall()

5、传输完毕后,关闭套接字
s.close()

TCP 客户端 1、创建套接字并链接至远端地址

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect()

2、链接后发送数据和接收数据

s.sendall()
s.recv()

3、传输完毕后,关闭套接字
s.close()

基于TCP的套接字

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
tcp服务端

# 1. 创建服务端的socket对象
serverSocket = socket.socket()
# 2. 绑定一个ip和端口, 客户端连接时的socket;
serverSocket.bind((HOST, PORT))
# 3. 一直监听是否有客户端连接
serverSocket.listen()
inf_loop:      #服务器循环链接   无限循环,接收多个链接
    # 4. 如果有客户端连接, 接收客户端的连接;
	# serverSocket.accept会返回2个值, address指的是, 客户端的ip和端口;
	#与客户端的connect相对应建立起来的链接
	#clientSocket三次握手建立起来的链接
	clientSocket, address = serverSocket.accept()
    comm_loop:         #通讯循环
        # 5. 客户端和服务端进行通信;
		data = clientSocket.recv(1024).decode('utf-8')
		print("接收到客户端的消息:", data)
		# 6. 给客户端回复消息
		clientSocket.send(b'hello client')
    clientSocket.close() 	#关闭链接 关闭三次握手即四次挥手
serverSocket.close()        #关闭服务器套接字(可选)

tcp客户端

# 1.
clientSocket = socket.socket()
# 2. 连接远程主机
clientSocket.connect((HOST, PORT))
#3 
comm_loop:        # 通讯循环
	# 4. 客户端, 服务端通信
	# 给server主机发送消息
	clientSocket.send(b'hello server')
	# 接收服务端的响应(即服务端回复的消息)
	recvData = clientSocket.recv(1024).decode('utf-8')
	print("接收到服务器的消息:", recvData)
#5.  关闭客户套接字
clientSocket.close()

Socket 编程实践之服务器端代码

from socket import  *

in_port=('127.0.0.1',8080)
back_log=5
buffer_size=1024



tcp_serve=socket(AF_INET,SOCK_STREAM)
tcp_serve.bind(in_port)
tcp_serve.listen(back_log)

print('服务端开始运行了')
conn,addr=tcp_serve.accept()   #服务端阻塞

print('双向链接',conn)
print('客户端地址',addr)

while True:

    data=conn.recv(buffer_size)
    print('来自客户端发送的消息',data.decode('utf-8'))
    conn.send(data.upper())

conn.close()
tcp_serve.close()

Socket 编程实践之客户端代码

from socket import  *

in_port=('127.0.0.1',8080)
back_log=5
buffer_size=1024

tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(in_port)

while True:
    msg=input('>>').strip()
    if len(msg) == 0:continue    #判断是否输入为空   防止两端卡住
    tcp_client.send(msg.encode('utf-8'))
    print('客户端已发送消息')
    data=tcp_client.recv(buffer_size)
    print('收到服务端发送到消息',data.decode('utf-8'))

tcp_client.close()

加上链接循环与通信循环

服务端改进版

# import socket
from socket import *
ip_port=('127.0.0.1',8080) #电话卡
back_log=5
buffer_size=1024

tcp_server=socket(AF_INET,SOCK_STREAM)      #买手机
tcp_server.bind(ip_port)                    #手机插卡
tcp_server.listen(back_log)                 #手机待机

while True:                  #新增接收链接循环,可以不停的接电话
    print('服务端开始运行了')
    conn,addr=tcp_server.accept() #服务端阻塞    手机接电话
    print('双向链接是',conn)
    print('客户端地址',addr)

    while True:    #新增通信循环,可以不断的通信,收发消息
        try:       # 防止客户端强制关闭,导致 data=conn.recv(buffer_size)卡住的现象
            data=conn.recv(buffer_size)    #听消息,听话
            print('客户端发来的消息是',data.decode('utf-8'))
            conn.send(data.upper())  #发消息,说话
        except Exception:
            break   # 终止
    #conn.close()       #挂电话

tcp_server.close()      #手机关机

客户端改进版
客户端1

#_*_coding:utf-8_*_

import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect_ex(ip_port)            #拨电话

while True:                      #新增通信循环,客户端可以不断发收消息
    msg=input('>>: ').strip()
    if len(msg) == 0:continue    #判断是否输入为空   防止两端卡住
    s.send(msg.encode('utf-8'))  #发消息,说话(只能发送字节类型)

    feedback=s.recv(BUFSIZE)     #收消息,听话
    print(feedback.decode('utf-8'))

s.close()                        #挂电话

客户端2

# import socket
from socket import *
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=1024

tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    tcp_client.send(msg.encode('utf-8'))
    print('客户端2已经发送消息')
    data=tcp_client.recv(buffer_size)
    print('收到服务端发来的消息',data.decode('utf-8'))

tcp_client.close()

一个服务端同时可以和两个客户端进行通信

验证客户端的合法性

如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

#服务端
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
from socket import *
import hmac,os

secret_key=b'linhaifeng bang bang bang'			#加盐
def conn_auth(conn):
    '''
    认证客户端链接
    :param conn:
    :return:
    '''
    print('开始验证新链接的合法性')
    msg=os.urandom(32)
    conn.sendall(msg)
    h=hmac.new(secret_key,msg)
    digest=h.digest()
    respone=conn.recv(len(digest))
    return hmac.compare_digest(respone,digest)

def data_handler(conn,bufsize=1024):
    if not conn_auth(conn):			#真正通讯之前验证客户端的合法性	  
        print('该链接不合法,关闭')
        conn.close()
        return
    print('链接合法,开始通信')
    while True:
        data=conn.recv(bufsize)
        if not data:break
        conn.sendall(data.upper())

def server_handler(ip_port,bufsize,backlog=5):
    '''
    只处理链接
    :param ip_port:
    :return:
    '''
    tcp_socket_server=socket(AF_INET,SOCK_STREAM)
    tcp_socket_server.bind(ip_port)
    tcp_socket_server.listen(backlog)
    while True:
        conn,addr=tcp_socket_server.accept()
        print('新连接[%s:%s]' %(addr[0],addr[1]))
        data_handler(conn,bufsize)

if __name__ == '__main__':
    ip_port=('127.0.0.1',9999)
    bufsize=1024
    server_handler(ip_port,bufsize)

#客户端
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
from socket import *
import hmac,os

secret_key=b'linhaifeng bang bang bang'
def conn_auth(conn):
    '''
    验证客户端到服务器的链接
    :param conn:
    :return:
    '''
    msg=conn.recv(32)
    h=hmac.new(secret_key,msg)
    digest=h.digest()
    conn.sendall(digest)

def client_handler(ip_port,bufsize=1024):
    tcp_socket_client=socket(AF_INET,SOCK_STREAM)
    tcp_socket_client.connect(ip_port)

    conn_auth(tcp_socket_client)

    while True:
        data=input('>>: ').strip()
        if not data:continue
        if data == 'quit':break

        tcp_socket_client.sendall(data.encode('utf-8'))
        respone=tcp_socket_client.recv(bufsize)
        print(respone.decode('utf-8'))
    tcp_socket_client.close()

if __name__ == '__main__':
    ip_port=('127.0.0.1',9999)
    bufsize=1024
    client_handler(ip_port,bufsize)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值