Python网络编程

  • 注意事项
  • Socket编程思路
  • 服务端
  • 客户端
  • TCP编程
  • 服务器端
  • 客户端
  • 多线程创建服务器
  • UDP编程


注意事项

  1. 在python3之后,socket传递的都是byte数据,字符串需要转换string.encode()。另一端接受Byte数据想要转为字符串,需要bytes.decode()。
  2. accept()和recv()方法都是阻塞。阻塞是指,程序会停在那里,一直等到有数据过来。

Socket编程思路

服务端

  1. 创建套接字,绑定套接字到本地IP与端口:
socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #创建套接字

bind()     #绑定ip

注:

socket.AF_INET  :  ipv4

socket.AF_INET6  :  ipv6

SOCK_STREAM :TCP

SOCK_DGRAM  :   UDP
  1. 开始监听 : s.listen()
  2. 进入循坏,不断接受客户端的连接请求:s.aceept()
  3. 接受传来的数据,或发送数据给对方 : s.recv() s.sendall()
  4. 传输完毕,关闭套接字 : s.close()

客户端

  1. 创建套接字,连接服务器地址:socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.connect()
  2. 连接后发送数据和接收数据:s.sendall(), s.recv()
  3. 传输完毕后,关闭套接字:s.close()

Python的Socket编程,通常分为TCP和UDP编程两种
前者是带连接的可靠传输服务,每次通信要握手,结束传输也要挥手,数据会被检验。
后者是不带连接的传输服务,简单粗暴不加控制和检查的一股脑将数据发送出去的方式,通常安全等级要求不高的业务场景,比如文件下载。

TCP编程

服务器端

#sever.py
import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket()  #创建套接字
sk.bind(ip_port)     #绑定服务地址
sk.listen(5) #监听连接请求
print('启动socket服务,等待客户端连接...')
conn,address = sk.accept()  #等待连接,此处自动阻塞
#死循环,等待客户端发送exit,才关闭连接
while True:
    client_data = conn.recv(1024).decode()
    if client_data == 'exit':
        exit("通信结束")

    conn.sendall('服务器已经收到你的信息'.encode()) #回馈信息给客户端
conn.close()

客户端

import socket
ip_port = ('127.0.0.1',9999)

s = socket.socket()
#连接服务器
s.connect(ip_port)

while True:
    inp = input("请输入要发送的内容:").strip()
    if not inp:
        continue
    s.sendall(inp.encode())

    if inp == "exit":#断开连接
        print("结束通讯")
        break
    server_reply = s.recv(1024).decode()
    print(server_reply)

s.close() #关闭连

多线程创建服务器

import socket
import threading

def link_handler(link,client):
    """
    该函数为线程需要执行的函数,负责具体的服务器和客户端之间的通信工作
    :param link:  当前线程处理的连接
    :param client:  客户端ip和端口信息,一个二元组
    :return: None
    """
    print("服务器开始接受来自[%s:%s]的请求..." % (client[0],client[1]))
    while True:
        client_data = link.recv(1024).decode()
        if client_data == "exit":
            print("结束与[%s:%s]的通信..." % (client[0],client[1]))
            break
        print("来自[%s:%s]的客户端向你发来信息:%s" % (client[0], client[1], client_data))
        link.sendall('服务器已经收到你的信息'.encode())
    link.close()

ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

print('启动socket服务,等待客户端连接...')


while True:
    conn,address = sk.accept()
    #没打过有新的连接,自动创建一个新的线程
    #并将连接对象和访问者的ip信息作为参数传递给线程的执行函数
    t = threading.Thread(target=link_handler,args=(conn,address))
    t.start()

多开几个客户端运行,可以看出,服务器能与多个客户端通信

UDP编程

由于UDP没有握手和挥手的过程,因此accept()和connect()方法都不需要。

# @Description : UDP服务端
import socket

ip_port = ('127.0.0.1',9998)

sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)  #创建套接字
sk.bind(ip_port)     #绑定服务地址


#死循环,等待客户端发送exit,才关闭连接
while True:
    client_data = sk.recv(1024).decode()
    print(client_data)
    if client_data == 'exit':
        exit("通信结束")
        break
sk.close()





# @Description : UDP客户端
import socket

ip_port = ('127.0.0.1', 9998)

sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
while True:
    inp = input('发送的消息:').strip()
    sk.sendto(inp.encode(), ip_port)
    if inp == 'exit':
        break

sk.close()