python socket

UDP Socket

UDP Client

import socket

# AF_INET是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信。
# socket.SOCK_DGRAM 代表UDP协议
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 发送方如果不绑定端口,操作系统会随机分配一个端口号
udp_socket.bind(("127.0.0.1", 9999))

while True:
    msg = input("请输入要发送的内容:")
    if msg == "exit":
        break
    # 需要编码为bytes---encode("utf-8")返回bytes
    udp_socket.sendto(msg.encode("utf-8"), ("127.0.0.1", 8888))

udp_socket.close()

在这里插入图片描述

在这里插入图片描述

UDP Server

import socket


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

# 绑定本地地址及监听的端口号
address = ("127.0.0.1", 8890)
udp_socket.bind(address)

while True:
    try:
        # 通过套接字接收数据,这里设定一次最多接收1024个字节
        # TODO 如果设置为10,但是发送的数据大于10个字节就会报
        #  WinError 10040,怎么避免这种问题?
        data = udp_socket.recvfrom(1024)
        # 因为当前是windows系统,所以解码为gbk,
        # 如果是linux这里应该是utf-8(要根据发送方的编码格式解码)
        msg = data[0].decode("gbk")
        address = data[1]
        print("from: %s, msg:%s" % (address, msg))
    except Exception as err:
        print("Err:%s" % err)
        break

udp_socket.close()

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

有收发功能UDP

注意:发送方发送了数据后,操作系统会缓存起来,接收方需要通过recvfrom来主动接收数据。并且,如果执行了recvfrom但是发送方没有发送数据,程序阻塞。

import socket

# 创建udp socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定接收消息地址
address = ("127.0.0.1", 8888)
udp_socket.bind(address)

while True:
    operate = input("请输入要使用的功能:\n0:发送数据\n1:接收数据\n2:退出程序\n")
    if operate == "0":
        ip = input("请输入接收方的ip地址:")
        port = int(input("请输入接收方的端口:"))
        msg = input("请输入要发送的消息:")
        udp_socket.sendto(msg.encode("gbk"), (ip, port))
        print("发送成功!")
    elif operate == "1":
        recv_msg = udp_socket.recvfrom(1024)
        print("receive from:%s ,msg:%s" % (recv_msg[1], recv_msg[0].decode("gbk")))
    elif operate == "2":
        print("exit!!!")
        break
    else:
        print("input error,please choose 0 or 1 or 2.")

udp_socket.close()

在这里插入图片描述

TCP Socket

TCP Client

import socket

# 创建tcp socket(使用socket.SOCK_STREAM),并连接指定address
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.connect(("127.0.0.1", 8890))

# 发送数据给服务器
tcp_socket.send(b"hahaha1111")

# 关闭连接
tcp_socket.close()

在这里插入图片描述

TCP Server

注意: 如下程序只能一次连接一个client,必须一个断开后再接受另一个连接。

from datetime import datetime
import socket


# 创建服务器socket,并监听8890端口
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.bind(("127.0.0.1", 8890))
tcp_socket.listen(128) # 同一时刻最多有个128个客户端连接

while True:
    print("Ready to accept.Time:%s" % datetime.now())
    # 这里会阻塞,直到收到客户端连接
    client_socket, client_addr = tcp_socket.accept()
    print("Accept client:%s.Time:%s" % (str(client_addr), datetime.now()))
    while True:
        # 这里会阻塞,直到客户端发送数据
        msg = client_socket.recv(1024)
        print("Client msg:%s. Time:%s" % (msg.decode("gbk"), datetime.now()))
        # 如果客户端关闭,recv将不会解阻塞,并且这里msg=b"",即服务端关闭也需要客户端连接
        if msg:
            # 服务端响应,并关闭客户端连接
            print("Begin response to client.")
            client_socket.send(b"server response")
        else:
            break
    client_socket.close()

tcp_socket.close()

在这里插入图片描述

TCP下载文件

download_server.py:

import os
import socket

tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.bind(("127.0.0.1", 8891))
tcp_socket.listen(128)

while True:
    client_socket, client_addr = tcp_socket.accept()
    print("client_addr:%s" % str(client_addr))
    file_name = client_socket.recv(1024).decode("utf-8")
    data = None
    if os.path.exists(file_name):
        with open(file_name, "rb") as fp:
            data = fp.read()
        print("Begin send data.")
        client_socket.send(data)
    else:
        print("file_name invalid.")
        client_socket.send(b"Error file_name")

tcp_socket.close()

download_client.py

import socket


tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.connect(("127.0.0.1", 8891))

file_name = "211.txt"
tcp_socket.send(file_name.encode("utf-8"))

data = tcp_socket.recv(1024)
if data and data.decode("utf-8") != "Error file_name":
   with open(file_name+".bak", "wb") as fp:
       fp.write(data)
else:
    print("file_name error.Begin exit.")

tcp_socket.close()

python多线程

python多线程主要用threading模块实现。

使用方法的形式创建多线程

import threading

count = 0


def run_thread():
    global count
    for i in range(100000):
        count += 1


t1 = threading.Thread(target=run_thread)
t2 = threading.Thread(target=run_thread)
t1.start()
t2.start()
t1.join()
t2.join()

print(count)

使用类的形式创建多线程

自定义类继承threading.Thread:

import threading

count = 0


class CountThread(threading.Thread):
    def run(self):
        global count
        for i in range(100000):
            count += 1


t1 = CountThread()
t2 = CountThread()
t1.start()
t2.start()
t1.join()
t2.join()

print(count)

互斥锁

如上,线程间共享全局变量,如果多个线程同时操作一个全局变量可能引起异常。
这个问题可以通过互斥锁解决,在访问全局变量时先获取锁对象,操作完后再释放锁对象。

import threading

count = 0
lock = threading.Lock()


class CountThread(threading.Thread):
    def run(self):
        global count
        for i in range(100000):
            # 锁范围要尽量小
            lock.acquire()
            count += 1
            lock.release()


t1 = CountThread()
t2 = CountThread()
t1.start()
t2.start()
t1.join()
t2.join()

print(count)

多任务版本的udp消息收发

启动两个线程分别用于接收和发送消息:

import threading
import socket


udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("127.0.0.1", 8890))


def recv(udp):
    while True:
        msg = udp.recvfrom(1024)
        print("recv from:%s, msg:%s" % (msg[1], msg[0].decode("gbk")))


def send(udp):
    while True:
        data = input("请输入要发送的内容:")
        udp.sendto(data.encode("utf-8"), ("127.0.0.1", 9999))


t1 = threading.Thread(target=recv, args=(udp_socket,))
t2 = threading.Thread(target=send, args=(udp_socket,))
t1.start()
t2.start()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值