前言.

        这个程序救了我一命,具体的后面再说

正文.

        作用.

                没啥好说的,作用肯定就是数据传输了,而且这个文件配合一些操作,甚至可以实现传文件

        导入.

                这次要用到一个很强大的python第三方库——socket

                不用非常仔细地去研究这个库,不过还是要背一些东西的

              UDP协议

                        今天就要用这个协议来传输

                        作为一种无连接协议,UDP他只管发送,不管接收(或者只管接收,不管发送),说白了就是我发出去就行了,接没接到关我屁事。也就是说,它可以绑定到任意端口(无论开没开),也能发送数据到任意端口。众所周知,一台机器不是所有端口都打开的(也许有,反正我没见过),而利用UDP的无连接特性,可以完美解决这种因为端口没打开而无法传输的问题,这也是为什么今天要用UDP。

                TCP协议

                        这是一种有连接协议

                        这个需要目标机器开启,且目标端口开启,如果没开启会连接失败,而且如果你连接成功,但是如果程序运行完了,你却没关闭连接,就会导致端口占用,然后就不能再连接了(除非手动关闭)。

        思路.

                如果要实现你说一句,我回一句,但如果你不说,我也不能说,你说完,我才能说,而且我不说完,你发的所有信息我都接收不到的这种功能,只用写一种程序。但想实现像微信、QQ那样实时传输,就要写两个(也不复杂,一个接收、一个发送,搞懂原理后其实很简单)

        需要用到的部分工具.

                1.socket

                        这里详细讲一下socket

                        socket可以指定协议,修改默认参数,发送、绑定、接收等等

                        首先是指定协议

                        你需要把协议指定到一个变量(变量名不能是python关键字,之前我用了python关键字socket,导致无法发送),如把UDP协议指定给变量s:

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

                        AF_INET指我们要用IPv4(类似123.123.123.123这种,IPv6是aa:aa:aa:aa:aa:aa这种),SOCK_DGRAM指UDP协议

                        这样就可以用s变量来做一些操作了

                        然后是修改默认参数

                        修改默认参数在UDP里作用不大,比较常用的只有一条:

                        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

                        这个可以设置端口复用,避免出现address already in use(端口被占用)

                        接着是发送、绑定、接收

                        首先是发送

                        发送需要指定发送内容(需要是字节,不能是其他类型)、目标IP(不必开启)、目标端口(不必开放),如我想发送"Hello"到192.100.100.100的12345端口:

                        client = 'Hello'

                        s.sendto(client.encode(), ('192.100.100.100', 12345))

                        client.encode()指把字符串类型的'Hello'转为字节类型

                        其实字节也可以用b'Hello'来表示,b表示bytes(字节)

                        (b''里面的东西不能是中文,不过client变量里面倒是能填中文,然后用encode来转换)

                        然后是绑定

                        用bind函数(感觉像谐音)

                        bind需要指定IP和端口,如我要绑定到192.160.100.100的123端口:

                        s.bind(('192.160.110.110', 123))

                        (注意:要两个括号)

                        对了,如果是绑定到本机,IP可以留空,但不能少双引号

                        最后是接收

                        用recvfrom函数(前提是要先绑定)

                        recvfrom要指定接受大小,然后会返回一个套接字,最大只能接收(发送)65435个字节,不然会导致缓冲区溢出。

                        如我要接收一个字节数小于等于200的信息(完整):

                        s.bind(("", 22))

                        response = s.recvfrom(200)

                        但是现在response里是内容加上套接字,如果只想获取内容,得这么写:

                        response = s.recvfrom(200)[0]

                        不过response是字节类型,想把它转为字符串,得这样:

                        response = response.decode()

                        如果想获取IP和端口:

                        addr = s.recvfrom(200)[1]

                        IP = addr[0]

                        port = addr[1]

                        如果都想获取:

                        response, addr = s.recvfrom(200)

                        response就是内容,addr[0]就是IP,addr[1]就是端口

                        不过这还不算完,还要说一下TCP

                        如果要指定TCP给一个变量:

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

                        这里一定要指定端口复用

                        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

                        然后是连接、发送、绑定、监听

                        连接(IP是192.1.1.1,端口是22):

                        s.connect(('192.1.1.1', 22))

                        如果连接成功,不会输出;如果失败,会输出Connection refused

                        发送(前提是连接成功):

                        client = 'Hello'

                        s.send(client.encode())

                        绑定和监听(前提是绑定成功):

                        s.bind(("192.1.1.1", 22))

                        s.listen(5)

                        response, addr = s.accept()

                        addr是一个套接字,addr[0]是IP,addr[1]是端口

                2.open函数

                        这个函数用来打开文件

                        open函数接收一个路径和一个操作符,然后要赋给一个变量

                        操作符有常用的三个参数:'w','a','r'

                        'w'用来覆盖写入,也就是说不管目标文件里面有什么,全部擦除,然后写入新的内容

                        'a'用来追加写入,也就是说不管目标文件里面有什么,在最后一个字符后面再写入新的内容

                        'r'用来读取,也就是说不管目标文件里面有什么,全部记录并赋给变量

                        然后open赋给变量后,变量有write()(写)、read()(读)两种操作,具体见下:

                        f = open('D:\python\text.txt', 'w')                      #覆盖写入

                        f.write('Hello')                                                  #写入'Hello'

                        这样,text.txt这个文件里就只有Hello五个字符

                        f = open('D:\python\text.txt', 'a')                      #追加写入

                        f.write(',word!')                                                #写入',word!'

                        这样,text.txt这个文件里就有Hello,word!十一个字符

                        f = open('D:\python\text.txt', 'r')                      #读取

                        response = f.read()                                        #把文件内容赋给response

                        这样,response的值就是'Hello,word!'

        代码.

                服务端.

import os

import socket

while True:

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(("", 22))

response, addr = s.recvfrom(4096)

if response != 'Do not show':

print("收到来自" + addr[0] + "的连接请求")

s.close()

time.sleep(1)

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.sendto(b'', (addr[0], 22))

print("连接已建立")

flag = 0

s.close()

while True:

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(("", 22))

response, addr = s.recvfrom(4096)

print("收到信息:" + response.decode())

s.close()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

if "你好" in response.decode():

client = "你好"

s.sendto(client.encode(), (addr[0], 22))

s.close()

print("本机回复:你好")

elif "=?" in response.decode():

client = response.decode()

start = 0

a = ""

while client[start] != "+" and client[start] != "-" and client[start] != "*" and client[start] != "/":

a += client[start]

start += 1

a = int(a)

c = client[start]

b = ""

start += 1

while client[start] != "=":

b += client[start]

start += 1

b = int(b)

if c == "+":

ans = str(a + b)

elif c == "-":

ans = str(a - b)

elif c == "*":

ans = str(a * b)

elif c == "/":

ans = str(a / b)

else:

ans = "???"

s.sendto(ans.encode(), (addr[0], 22))

s.close()

print("本机回复:" + ans)

elif "再见" in response.decode():

client = "再见"

s.sendto(client.encode(), (addr[0], 22))

s.close()

print("本机回复:再见")

print("结束聊天")

break

elif "给爷关闭" == response.decode():

client = '特殊命令!退出程序......'

s.sendto(client.encode(), (addr[0], 22))

s.close()

flag = 1

print("本机回复:特殊命令!退出程序......")

break

elif "命令模式" == response.decode():

client = "命令模式"

s.sendto(client.encode(), (addr[0], 22))

s.close()

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

response, addr = s.recvfrom(4096)

if response.decode() == "结束命令模式":

s.close()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

shu = "已结束"

s.sendto(shu.encode(), (addr[0], 22))

s.close()

break

shu = "\n" + os.popen(response.decode()).read()

s.close()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.sendto(shu.encode(), (addr[0], 22))

s.close()

print("本机回复:" + shu)

elif response.decode() == "clear":

shu = os.popen(response.decode()).read()

s.close()

elif "请说:" in response.decode():

client = response.decode()

client = client[3:len(client)]

s.sendto(client.encode(), (addr[0], 22))

s.close()

elif response.decode() == "文件下载":

s.bind(("", 22))

lujing = s.recvfrom(4096)[0]

s.close()

lujing = lujing.decode()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

if lujing[len(lujing) - 1] == '/':

lujing = lujing[0:len(lujing) - 1]

print("尝试打开" + lujing)

f = open(lujing, 'r')

print("打开成功")

response = f.read()

s.sendto(response.encode(), (addr[0], 22))

print("已发送")

s.close()

else:

client = "我的主人尚未设置对此消息的回复"

s.sendto(client.encode(), (addr[0], 22))

s.close()

print("本机回复:我的主人尚未设置对此消息的回复")

if flag == 1:

break

                        就是文件下载还有算数的地方比较麻烦,你也可以拓展一些其他功能,有些地方可能不理解,我再把客户端代码贴上

                客户端.

import sys

import socket

ip = input("连接到:")

print("连接中(若连接时间过长,可自行停止)")

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.sendto(b'', (ip, 22))

s.close()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(("", 22))

try:

response, addr = s.recvfrom(4096)

print("连接成功")

except KeyboardInterrupt:

print("连接失败")

s.close()

sys.exit()

s.close()

while True:

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

client = input("发送消息:")

if client == "文件下载":

pan = input("路径:")

s.sendto(client.encode(), (ip, 22))

lu = input("保存路径:")

f = open(lu, 'w')

s.sendto(pan.encode(), (ip, 22))

s.close()

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

s.bind(("", 22))

response = s.recvfrom(65435)[0]

if response.decode() == "error":

print("服务端没有对应文件,取消下载......")

s.close()

continue

f.write(response.decode())

f.close()

s.close()

print("下载成功")

continue

s.sendto(client.encode(), (ip, 22))

s.close()

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(("", 22))

response, addr = s.recvfrom(4096)

print("收到回复:" + response.decode())

s.close()

if "再见" in client or "......" in response.decode():

break

写在最后,救命程序

        之前不是运行了病毒吗(可以翻我以前的文章)?然后重装了系统,由于之前电脑上有一些比较重要的文件,我怕重装后就没了,然后利用没关闭的终端,运行了这个程序上传文件到另一个电脑,然后重装系统,再敲了一个接收文本的普通程序,然后从另一个电脑再上传回来。

        啧,我这机智的大脑(我知道很不要脸,但我还是要说)

拓展-基于UDP的聊天器

        直接放代码

        发送端.

import socket

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

ip = input("IP:")

try:

while True:

client = input("")

s.sendto(client.encode(), (ip, 22))

except:

s.close()

        接收端.

import socket

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

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(("", 22))

ip = ""

try:

while True:

response, addr = s.recvfrom(65435)

if addr[0] != ip:

print(addr[0]:)

ip = addr[0]

print(response.decode())

except:

s.close()

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: