socket套接字的学习与简单应用

Posted saoqiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket套接字的学习与简单应用相关的知识,希望对你有一定的参考价值。

技术图片

技术图片

socket套接字

Socket又称为套接字,它是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口提高了效率
socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。也
为什么存在socket抽象层?
如果直接与操作系统数据交互非常麻烦,繁琐,socket对这些繁琐的的操作高度的封装,简化.   
socket在python中就是一个模块.

基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

tcp链接+循环 通信 服务端常驻

技术图片

server端

import socket
phone=socket.socket()#买手机
phone.bind(('127.0.0.1',6666))#绑卡
phone.listen(5)#设置连接数一个连接加5个等待 缓存池
while 1:
    conn,addr=phone.accept()
    print(f'用户{addr}来了')
    while 1:
        try:
            from_client_data=conn.recv(1024)
            if from_client_data.decode('utf-8')=='Q':
                print('正常断开')
                break
            print(f'来自客户端{addr}消息{from_client_data.decode("utf-8")}')
            to_client_data=input('>>>>>>>')
            conn.send(to_client_data.encode('utf-8'))
        except Exception:
            break
    conn.close()
phone.close()

client端

# 自己的
import socket
phone=socket.socket()
phone.connect(('127.0.0.1',6666))
while 1:
    to_server_data=input('>>>>>>q退出')
    if not to_server_data:
        print('不可以输入空')
        continue
    phone.send(to_server_data.encode('utf-8'))#因为不可以让他发空 所以放在判断下
    if to_server_data.upper()=='Q':
        break
    from_server_data=phone.recv(1024)
    print(f'来自客户端消息{from_server_data.decode("utf-8")}')
phone.close()

tcp执行远端命令

server端

# 用到的模块
import subprocess
# import subprocess
# obj = subprocess.Popen('系统命令',
#                        shell=True,
#                        stdout=subprocess.PIPE,
#                        stderr=subprocess.PIPE,
#                        )
# print(obj.stdout.read().decode('gbk'))  # 正确命令
# print(obj.stderr.read().decode('gbk'))  # 错误命令
# 错误的是空字符串

import socket
import subprocess
phone = socket.socket()

phone.bind(('127.0.0.1',8848))

phone.listen(2)
while 1:
    conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
    print(f'链接来了: {conn,addr}')
    while 1:
        try:
            from_client_data = conn.recv(1024)  # 最多接受1024字节
            if from_client_data.upper() == b'Q':
                print('客户端正常退出聊天了')
                break
            obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   )
            result = obj.stdout.read() + obj.stderr.read()

            conn.send(result)
        except ConnectionResetError:
            print('客户端链接中断了')
            break
    conn.close()
phone.close()

client端

# 用到的模块
import subprocess
# import subprocess
# obj = subprocess.Popen('系统命令',
#                        shell=True,
#                        stdout=subprocess.PIPE,
#                        stderr=subprocess.PIPE,
#                        )
# print(obj.stdout.read().decode('gbk'))  # 正确命令
# print(obj.stderr.read().decode('gbk'))  # 错误命令
# 错误的是空字符串

import socket
import subprocess
phone = socket.socket()

phone.bind(('127.0.0.1',8848))

phone.listen(2)
while 1:
    conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
    print(f'链接来了: {conn,addr}')
    while 1:
        try:
            from_client_data = conn.recv(1024)  # 最多接受1024字节
            if from_client_data.upper() == b'Q':
                print('客户端正常退出聊天了')
                break
            obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   )
            result = obj.stdout.read() + obj.stderr.read()

            conn.send(result)
        except ConnectionResetError:
            print('客户端链接中断了')
            break
    conn.close()
phone.close()

利用udp建立通讯

udp是无链接的,先启动哪一端都不会报错

技术图片

server端

import socket

udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)  # 基于网络,udp协议的socket

udp_server.bind(('127.0.0.1', 9000))#绑卡

while 1:
    from_client_data = udp_server.recvfrom(1024)#接收 前面消息 后面是ip端口
    print(f'来自{from_client_data[1]}的消息:{from_client_data[0].decode("utf-8")}')
    to_client_data = input('>>>').strip()
    udp_server.sendto(to_client_data.encode('utf-8'),from_client_data[1])

client端

import socket

udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)  # 基于网络,udp协议的socket

while 1:
    to_server_data = input('>>>').strip()
    udp_client.sendto(to_server_data.encode('utf-8'),('127.0.0.1', 9000))
    from_server_data = udp_client.recvfrom(1024)#发送端 端口不知道
    print(f'来自{from_server_data[1]}的消息:{from_server_data[0].decode("utf-8")}')

tcp实现文件上传 客户端-->服务端

server端

# 1. 接收固定长度的4个字节 2. 利用struct反解 3. 接收bytes类型的报头 4. 将bytes类型的报头转化成json
# 5. 将json类型报头转化成字典形式的报头有一个MD5校验# 6. 接收原始数据
#在文件读取时同时进行md5效验 一举两得
import socket
import struct
import json
import os
import hashlib
MY_FILE = os.path.join(os.path.dirname(__file__),'my_file')#拼接出来的要存入的总路径

def socket_server(MY_FILE):
    server = socket.socket()
    server.bind(('127.0.0.1',8848))
    server.listen(5)
    conn, addr = server.accept()
    four_bytes = conn.recv(4)#1 接收固定长度的4个字节
    head_len = struct.unpack('i',four_bytes)[0]#2  利用struct反解
    head_dic_json_bytes = conn.recv(head_len)#3接收bytes类型的报头
    head_dic_json = head_dic_json_bytes.decode('utf-8')#4 将bytes类型的报头转化成json
    head_dic = json.loads(head_dic_json)#5将json类型报头转化成字典形式的报头
    with open(os.path.join(MY_FILE,head_dic['new_file_name']),mode='wb') as f1:#6接收原始数据

        total_size = 0
        ret = hashlib.md5()
        while total_size < head_dic['file_size']:
            every_data = conn.recv(1024)
            f1.write(every_data)
            total_size += len(every_data)
            ret.update(every_data)
        if ret.hexdigest()==head_dic['MD5']:
            print('md5效验成功')
        else:
            print('md5效验失败')
            os.remove(os.path.join(MY_FILE,head_dic['new_file_name']))
    conn.close()
    server.close()
socket_server(MY_FILE)

client端

# 1.制作字典形式的报头2. 获取json形式的报头 3. 获取bytes形式的报头4. 获取bytes报头的总字节数 5. 将bytes报头的总字节数转化成固定4个字节#
# 6. 发送固定的4个字节 7.发送报头 8. 发送总数据
# 循环条件设定:1. 根据总子节数: file_size: 493701, 每次循环1024个,2. 每次取数据不为空,即可.
import socket
import os
import json
import struct
import hashlib
FILE_PATH = os.path.join(os.path.dirname(__file__), 'demo.mp4')#拼接出来的总路径
def md5_file(path):
    ret = hashlib.md5()
    with open(path,mode='rb') as f1:
        while 1:
            content = f1.read(1024)
            if content:
                ret.update(content)
            else:
                return ret.hexdigest()
def socket_client(path,md5,name):
    client = socket.socket()
    client.connect(('127.0.0.1',8848))
    head_dic = {#1.制作字典形式的报头
        'MD5': md5,
        'file_name':path,#路径
        'file_size': os.path.getsize(FILE_PATH),#利用文件路径判断文件大小
        'new_file_name': name,#文件名
    }
    head_dic_json = json.dumps(head_dic)#2. 获取json形式的报头
    head_dic_json_bytes = head_dic_json.encode('utf-8')#3. 获取bytes形式的报头
    head_len = len(head_dic_json_bytes)#4. 获取bytes报头的总字节数
    four_bytes = struct.pack('i',head_len)#5. 将bytes报头的总字节数转化成固定4个字节
    client.send(four_bytes)#6. 发送固定的4个字节
    client.send(head_dic_json_bytes)#7.发送报头
    with open(FILE_PATH,mode='rb') as f1:# 8. 发送总数据
        while 1:
            every_data = f1.read(1024)
            if every_data:
                client.send(every_data)
            else:
                break
    client.close()
socket_client(FILE_PATH,md5_file(FILE_PATH),'demo1.mp4')

tcp实现文件下载 服务端-->客户端

qq聊天的代码

server

基于UDP协议的socket通信

server

import socket
server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 基于网络的UDP协议的socket
server.bind(('192.168.14.198',9000))

while 1:

    from_client_data = server.recvfrom(1024)  # 阻塞,等待客户来消息
    print(f'33[1;35;0m来自客户端{from_client_data[1]}: {from_client_data[0].decode("utf-8")} 33[0m')
    # to_client_data = input('>>>').strip()
    # server.sendto(to_client_data.encode('utf-8'),from_client_data[1])


# 1. 基于udp协议的socket无须建立管道,先开启服务端或者客户端都行.
# 2. 基于udp协议的socket接收一个消息,与发送一个消息都是无连接的.
# 3. 只要拿到我的ip地址和端口就都可以给我发消息,我按照顺序接收消息.

client端

import socket
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 基于网络的UDP协议的socket

while 1:

    to_server_data = input('>>>:').strip()
    client.sendto(to_server_data.encode('utf-8'),('127.0.0.1',9000))
    # data,addr = client.recvfrom(1024)
    # print(f'来自服务端{addr}消息:{data.decode("utf-8")}')

摘抄题

1.简述socket套接字
2,执行远端命令用到的模块
3.文件上传下载

以上是关于socket套接字的学习与简单应用的主要内容,如果未能解决你的问题,请参考以下文章

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

Qt学习 之 Socket通信(世界上最简单的例子了)

网络编程之套接字socket

网络编程(待补充)

socket之tcpudp

一次与两个用户随机聊天(Socket.io)