【小沐学Python】Python实现socket网络通信

66 篇文章 12 订阅

🍺SOCKET网络通信系列文章链接如下:🍺
🎈【小沐学python】(一)Python简介和安装🎈
🎈Python实现socket网络通信🎈
🎈C++实现socket网络通信🎈
🎈Android实现socket网络通信🎈
🎈nodejs实现socket网络通信🎈
在这里插入图片描述

1、简介

Python 提供了两个级别访问的网络服务:

  • 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统 Socket 接口的全部方法。
  • 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

2、获取本机IP地址

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_tcp_server.py
# creator: tomcat
# date: 2021-11-16

from socket import *

def get_host_ip():
    s = 0
    try:
        s = socket(AF_INET, SOCK_DGRAM)
        s.connect(('1.1.1.1', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()

    return ip

ip1 = get_host_ip()
print(ip1)

IP2 = gethostbyname(gethostname())
print(ip2)

3、TCP方式

3.1 服务端(只支持一个客户端访问)

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_tcp_server.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from time import ctime
from datetime import datetime

HOST = ''
PORT = 27015
BUFSIZ = 1024
ADDR = (HOST, PORT)

s = socket(AF_INET, SOCK_STREAM)
s.bind(ADDR)
s.listen(5)

while True:
    print('waiting for clients ...')
    c, addr = s.accept()
    t = datetime.now ().strftime ('%H:%M:%S')
    print('   connnecting from: [', t, "]", addr)

    while True:
        data = c.recv(BUFSIZ)
        if not data:
            break
        print("recv: ", data )
        c.send(('[%s] %s' % (ctime(), "A message from python server.")).encode())
    c.close()
    s.close()

运行结果如下:
在这里插入图片描述
测试对应的客户端(C++),运行结果如下:
在这里插入图片描述

3.2 服务端(支持多个客户端并发访问,版本1)

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# !/usr/bin/env python
# coding=utf-8
# filename:test_tcp_server.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from time import ctime
from datetime import datetime
import threading

IP = gethostbyname(gethostname())
print("本机IP: ", IP)
ADDR = (IP, 12345)
BUFSIZ = 1024

s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(ADDR)
s.listen(5)
socks = []  # 放每个客户端的socket


def handle():
    while True:
        for c in socks:
            try:
                data = c.recv(BUFSIZ) 
            except Exception as e:
                continue
            if not data:
                socks.remove(c)
                continue

            st = datetime.now().strftime('%H:%M:%S')
            print("   recv: %s, %s, %s" % (c.getpeername(), st, data))
            c.send(('[%s],%s' % (ctime(), data)).encode())


t = threading.Thread(target=handle)
if __name__ == '__main__':
    t.start()
    print('waiting for connecting...')
    while True:
        clientSock, addr = s.accept()
        print('   connected from:', addr)
        clientSock.setblocking(False)
        socks.append(clientSock)

s.close()

运行结果如下:
在这里插入图片描述

3.3 服务端(支持多个客户端并发访问,版本2)

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# !/usr/bin/env python
# coding=utf-8
# filename:test_tcp_server.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from time import ctime
from datetime import datetime
import threading

IP = gethostbyname(gethostname())
print("本机IP: ", IP)
ADDR = (IP, 12345)
BUFSIZ = 1024

s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(ADDR)
s.listen(5)  # 最大连接数
socks = []  # 放每个客户端的socket


def connect_handle(c, addr):
    while True:
        recvdata = c.recv(BUFSIZ) 
        if recvdata == 'exit' or not recvdata:
            break

        st = datetime.now().strftime('%H:%M:%S')
        print("   recv: %s, %s, %s" % (c.getpeername(), st, recvdata))

        msg = str(recvdata) + ' from python sever.'
        c.send(msg.encode())
    c.close()


while True:
    c, c_addr = s.accept()
    print('   connect from:', c_addr)

    t = threading.Thread(target=connect_handle, args=(c, c_addr))
    t.start()

s.close()

3.3 客户端

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_tcp_client.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from time import ctime
from datetime import datetime

BUFSIZ = 1024
ADDR = ('127.0.0.1', 27015) # or 'localhost'

c = socket(AF_INET, SOCK_STREAM)
c.connect(ADDR)
while True:
    data = input('Input: ')
    if not data:
        break
    c.send(data.encode())
    data = c.recv(BUFSIZ)
    if not data:
        break

    t = datetime.now().strftime('%H:%M:%S')
    print("[", t,"]",data.decode('utf-8'))
c.close()

运行结果如下:
在这里插入图片描述
测试对应的服务端(C++),运行结果如下:
在这里插入图片描述

4、UDP方式

4.1 发送端

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_udp_client.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from datetime import *

BUFSIZ = 1024
ADDR = ('127.0.0.1', 27015) # or 'localhost'

c = socket(AF_INET, SOCK_DGRAM)

while True:
    data = input('Input: ')
    if not data:
        break
    c.sendto(data.encode(), ADDR)
    data = c.recvfrom(BUFSIZ)
    if not data:
        break

    t = datetime.now().strftime('%H:%M:%S')
    print("[", t,"]", data)
c.close()

运行结果如下:
在这里插入图片描述
测试对应的接收端(C++),运行结果如下:
在这里插入图片描述

4.2 接收端

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_udp_server.py
# creator: tomcat
# date: 2021-11-16

from socket import *
from time import ctime
from datetime import datetime

BUFSIZ = 1024
ADDR = ('127.0.0.1', 27015) # or 'localhost'

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

while True:
    print('waiting for clients ...')
    data, addr = s.recvfrom(1024)
    t = datetime.now ().strftime ('%H:%M:%S')
    print('   connnecting from: [', t, "]", addr)

    data = data.decode()
    if not data:
        break
    print('[Received]', data)
    send = input('Input: ')
    s.sendto(send.encode(), addr) 
s.close()

运行结果如下:
在这里插入图片描述
测试对应的发送端(C++),运行结果如下:
在这里插入图片描述

5、HTTP方式

import requests
import base64

def acces_api_with_cookie(url_login,USERNAME,PASSWORD,url_access):

    # Start a session so we can have persistant cookies
    session = requests.session()

    # This is the form data that the page sends when logging in
    login_data = {
        'username': USERNAME,
        'password': PASSWORD,
        'submit': 'login',
    }

    # Authenticate
    r = session.post(url_login, data=login_data)

    # Try accessing a page that requires you to be logged in
    r = session.get(url_access)
    #print r.content
    #print r.text
    print(r.status_code)
    return r.content

    #print r.content

id = 1
title = base64.b64encode("wuhan")
studytime = "a"
operat="b"
warning="c"
report="d"
table="portal_post"
url=base64.b64encode('{"action":"portal\/Article\/index","param":{"id":2}}')

url_full = "http://192.168.88.116/user/favorite/add?id="+str(id)\
           +"&title="+title\
           +"&studytime="+studytime\
           +"&operat="+operat\
           +"&warning="+warning\
           +"&report="+report\
           +"&table="+table\
           +"&url="+url
print(url_full)

acces_api_with_cookie("http://192.168.88.116/user/login/dologin.html","admin","admin888", url_full)

6、WebSocket

  • The WebSocket Protocol

The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security model commonly used by web browsers. The protocol consists of an opening handshake followed by basic message framing, layered over TCP. The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g., using XMLHttpRequest or s and long polling).
在这里插入图片描述

6.1 安装websockets库

$ pip install websockets

在这里插入图片描述

$ pip list

在这里插入图片描述

6.2 服务端

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_websocket_server.py
# description: WS server example
# creator: tomcat
# date: 2021-11-16

import asyncio
import websockets

async def main_loop(ws, path):
    name = await ws.recv()
    print(f"< {name}")

    msg = f"Python server: {name}!"
    print(f"> {msg}")
    await ws.send(msg)

start_server = websockets.serve(main_loop, '127.0.0.1', 12345)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

运行结果如下:
在这里插入图片描述
测试对应的客户端(js)如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
    <title></title>
    <script src="http://code.jquery.com/jquery-1.4.1.min.js"></script>
    <script>
        var ws;
        $().ready(function () {
            $('#conn').click(function () {
                //ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port);
                ws = new WebSocket($('#user').val()); 

                $('#msg').append('<p>正在连接...</p>');

                ws.onopen = function () {
                    $('#msg').append('<p>已经连接</p>');
                }
                ws.onmessage = function (evt) {
                    var myDate = new Date();
                    var mytime=myDate.toLocaleTimeString();
                    $('#msg').append('<p>' + mytime + ': ' + evt.data +'</p>');
                }
                ws.onerror = function (evt) {
                    $('#msg').append('<p>' + JSON.stringify(evt) + '</p>');
                }
                ws.onclose = function () {
                    $('#msg').append('<p>已经关闭</p>');
                }
            });

            $('#close').click(function () {
               ws.close();
            });

            $('#send').click(function () {
                if (ws.readyState == WebSocket.OPEN) {
                    ws.send( $('#content').val() );
                }
                else {
                    $('#tips').text('连接已经关闭');
                }
            });
        });
    </script>
</head>
<body>
    <div>
        <input id="user" type="text" value='ws://127.0.0.1:12345' />
        <input id="conn" type="button" value="连接" />
        <input id="close" type="button"  value="关闭"/><br />
        <span id="tips"></span>
        <input id="content" type="text" />
        <input id="send" type="button"  value="发送"/><br />
        <div id="msg">
        </div>
    </div>
</body>
</html>

浏览器chrome的运行结果如下:
在这里插入图片描述
Wireshark 抓取webscoket如下:
在这里插入图片描述
在这里插入图片描述

6.3 客户端

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# filename:test_websocket_server.py
# description: WS client example
# creator: tomcat
# date: 2021-11-16

import asyncio
import websockets


async def main_loop():
    async with websockets.connect('ws://localhost:12345') as ws:
        name = input(">")

        await ws.send(name)
        print(f"> {name}")

        msg = await ws.recv()
        print(f"< {msg}")


asyncio.get_event_loop().run_until_complete(main_loop())

7、通信协议

通信协议是指双方实体完成通信或服务所必须遵循的规则和约定,比喻双方沟通约定用"普通话"交流一样。协议定义了数据单元使用的格式,信息单元应该包含的信息与含义、连接方式、信息发送和接收的时序,从而确保网络中数据顺利地传送到确定的地方。

在这里插入图片描述

7.1 MODBUS协议

全面定义了数据传输和电器特性,Modbus协议目前应用于串口、以太网以及其他支持互联网协议的网络中,大多数Modbus设备通信通过串口EIA-485物理层进行。

在这里插入图片描述

7.2 并口协议

仅仅定义了电器特性,8080定义了SET、A/D、W/R、D0D7共11根信号线。其中:SET为写入控制,主机或从机在下降沿将地址或数据发送到双向并口D0D7;A/D为地址/数据选择控制,A/D=0时表示传送数据,A/D=1时表示传送地址;W/R为读/写控制,W/R=0时表示主机读从机,W/R=1时表示主机写从机;D0~D7为双向数据地址总线,配合W/R和A/D进行地址和数据的双向传输。

7.3 串口协议

仅仅定义了电器特性,串口按bit位发送和接收字节。尽管比特字节byte的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议规定了数据包的起始位、主体数据、校验位及停止位,通信双方需要约定一致的数据包格式。在串口通信中,常用的协议包括RS-232、RS-422和RS-485。

8、通信接口

通信接口串口与并口:串口好比一条车道,只能一位一位地传输数据;并口是8个车道同一时刻传送8位数据。并口因8位通道之间存在着互相干扰,传输时速度受到限制,且传输出错时,需同时重新传8个位数据,而串口没有干扰,传输出错后重发一位就可以了,所以要比并口快。

在工业现场常见的通信接口有:串口232、485、422;以太网;GPIB;USB;无线;光纤等。

8.1 并口

IEEE1284标准规定了3种连接器,分别称为A、B、C型。

8.2 串口

串口通信常见为异步传输,只要一对传输线就可以实现双向通信,其特点是:数据按位顺序传送,成本低但传送速度慢;传输距离可以从几米到几千米;根据信息的传送方向,串行通讯可分为单工、半双工和全双工三种。

  • (1)RS232
    采用单端全双工传输,相对于TTL/CMOS优点是提高了电平幅度提高了抗干扰能力,信号传输距离提高到15米;缺点是电压上升时间延长,传输速率较低,波特率最高19200bund/s。采用共地传输抗干扰能力较差。

计算机通讯接口之一,通常 RS-232 接口以9个引脚 (DB-9) 或是25个引脚 (DB-25) 的形态出现,一般个人计算机上会有两组 RS-232 接口,分别称为 COM1 和 COM2。

在这里插入图片描述

  • (2)RS485
    采用差分信号传输,抗干扰能力强,传输距离能够达到上千米。能够传输的信号最低可以低至200mv,传输速率最高可以达到10Mbund/s。两线间电压差+2V+6V表示逻辑1;两线间电压差-2-6V表示逻辑0。采用半双工通信,只能有一个主机处在发送状态,因此必须使用使能信号来控制设备的发送接收状态。RS485可以实现一对多通信,总线上允许的连接的设备理论上最多可以达到128个。

RS485无具体的物理形状,根据工程的实际情况而采用的接口。
在这里插入图片描述

  • (3)RS422
    在RS485的基础上,由半双工>全双工,采用单独的发送和接收通道,为4线接口,因此不必控制数据方向。RS422支持点对多的双向通信,最多可以接10个节点,一个主设备,其余为从设备,从设备之间不能通讯。接收端终端100Ω的端接电阻吸收长距离传输信号时反射和回波。

  • (4)CAN总线
    没有主机也没有从机,采用差分信号传输,每个控制单元都有一个收发器,随时可以向总线发送信息和接收数据。采用优先级传输数据,级别高的先传送。CAN总线是一种串行总线,不是并行的,是用来传输电子数据的,就像串口总线、USB总线、 以太网 一样;

8.3 以太网口

常见的以太网接口类型有:SC光纤、RJ-45、FDDI、AUI、BNC、Console,最常用的是RJ-45接口。同类设备采用交叉互联法,一端用T568A,另一端用T568B;异种设备采用直连互联法,即两端都用T568B。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.4 USB接口

USB 总线作为一种高速串行总线,其极高的传输速度可以满足高速数据传输的应用环境要求。BUS总线具备:兼有供电;支持即插即用和热插拔;支持控制传输、等时传输、中断传输、数据块传输;通过集线器最多可扩展127 个外设;兼容良好等优点。通用串行总线USB已逐渐替代串口和并口。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

8.5 视频接口

在这里插入图片描述

  • (1)常见的四种视频接口类型有:VGA、HDMI、DVI、DP,其中最为普及的接口是VGA,这种流行了几十年的接口,由于自身性能的缺陷,现在逐渐被其它接口取代,其中最抢眼的就是HDMI;

  • (2)VGA和DVI接口不能同步传输音频,而HDMI和DP既能高清传输视频也能同步音频;所以当HDMI(或DP)转VGA(或DVI)时,音频信号会丢失,所以如果要输出音频,需要额外连接音频线。

  • (3)目前四种视频接口支持视频最大分辨率不同,从低到高的顺序是:VGA、DVI、HDMI、DP,所以由低分辨率的端口转换为高分辨率的端口时,不会影响画质,比如DVI转HDMI,反之则会影响画质,以下是视频接口规格表,可以看出,HDMI2.1版本支持8K分辨率,而VGA 最高只能支持1080P分辨率。

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!



在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值