Python套接字编程Socket Progaming——1

本篇文章是Network And Web Programing-Socket Programing分类中的第一篇文章,内容主要包含

  1. Socket概念理解
  2. Socket programing介绍
  3. 一个简单的TCP协议的server-client程序
  4. 支持同时处理多个客户端简单server-client连接程序
  5. socket的常用选项使用

理解socket概念

一个socket确定了网络中两个应用的端口之间的唯一连接方式,一个socket包含三个部分:协议方式(TCP, UDP或IP)、IP地址和端口号PORT,端口号是一个整数代表着一个进程,为了唯一确定端口之间连接,还需要指定使用的协议类型(及其信息),这些唯一确定了两个结点之间的连接的信息就是socket,有时候socket和port会视作同义词来使用,但是需要注意两者是不同的

Socket编程

套接字编程是一种在网络中两个结点连接和交流的方式,其中一个socket(结点)绑定并监听一个特定IP的PORT的请求,另一个socket则向这个IP的PORT发送请求形成连接,监听的一方为服务端,主动发送连接请求的一段为客户端

连接百度服务端的代码示例
连接到一个服务端需要知道它的IP和开放连接的端口,连接时IP不能填域名,可以通过ping www.baidu.com获取百度的IP,或者在代码中这样获取

import socketip = socket.gethostbyname("www.baidu.com")
print(ip)	# 163.177.151.109

连接到服务端

ip = socket.gethostbyname("www.baidu.com")
port = 80   # 默认开放的端口
ipaddress = (ip, port)sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(ipaddress)
print(f"Successfully connected to baidu server on port: {ipaddress}")

输出:

Successfully connected to baidu server on port: ('163.177.151.109', 80)

socket包含两个参数
第一个参数涉及到socket支持的IP地址族类,AF_INET表示ipv4类,对于socket只有下面三种族类可用

AF_UNIX 
AF_INET 
AF_INET6 

AF_UNIX族类socket可以提供单个系统之间进程的交流,AF_UNIX族类支持数据流和数据报类型的socket(类型在第二个参数介绍)
AF_INET和AF_INET6族类socket可以提供不同系统之间进程的交流,也支持数据流和数据报类型的socket

第二个参数是socket的类型,SOCK_STREAM表示面向连接TCP的协议,socket的类型取决于两个结点之间传递的数据的性质(例如稳定性、顺序一致性和重复信息的处理方式等),以下是定义在unix系统sys/socket.h文件中标准的socket类型

/*Standard socket types */
#define  SOCK_STREAM             1 /*virtual circuit*/
#define  SOCK_DGRAM              2 /*datagram*/
#define  SOCK_RAW                3 /*raw socket*/
#define  SOCK_RDM                4 /*reliably-delivered message*/
#define  SOCK_CONN_DGRAM         5 /*connection datagram*/

知道怎么建立一个socket连接之后,现在需要怎么使用socket连接发送数据,socket库支持socket使用sendall方法发送数据,客户端可以发送数据,服务端也可以用这个方法发送数据

一个简单的server-client程序

server:
实现包含以下步骤

  • 服务端需要使用bind()方法绑定到一个特定的IP和端口号
  • 使用listen()方法监听这个端口
  • 当接收到连接请求时使用accept()方法初始化一个socket的连接
  • 然后对这个连接使用recv方法接收客户端发送的数据并交给程序处理
  • 最后使用close()方法关闭socket连接
# server.py
import socketdef mian():ip = socket.gethostname()ipaddress = (ip, 12345)# ipaddress = ("", 12345)     # socket bind的ip传入空字符串时让服务器可以监听网络中其他电脑的请求sk = socket.socket()sk.bind(ipaddress)sk.listen(5)       # 指定系统允许的最大连接数,超过时会拒绝新的连接while True:conn, addr = sk.accept()conn.send(b"Got a connection from server")data = conn.recv(1024)print(f"received data from client: {data}")conn.close()if __name__ == "__main__":mian()      

在命令行运行server.py后开启服务,等待客户端的连接请求
client:
包含两个步骤

  • 创建socket对象
  • 连接到指定的ip地址
# client.py
import socketdef main():ip = socket.gethostname()port = 12345ipaddress = (ip, port)sk = socket.socket()sk.connect(ipaddress)sk.send(b"Hello")data = sk.recv(1024)print(f"receive data from server: {data}")sk.close()if __name__ == "__main__":main()

在另外一个命令行运行client.py,就会向server发送请求

# server output:
received data from client: b'Hello'
received data from client: b'Hello'
...# client output: 
receive data from server: b'Got a connection from server'

使用在socket之上封装的socketserver编写TCP连接以及多线程支持多个客户端连接

server:

# -*- coding:utf-8 -*-
"""
一个简单的应答服务器
socketserverTCPServer: 在socket之上封装的方便操作各种类型socket连接的类,默认是TCP连接
BaseRequestHandler: socket响应处理的基类,无实际实现功能属性request: 属性是客户端socket,属性client_address: 包含服务器绑的定IP和端口号
"""
import socket
import time
from socketserver import TCPServer, BaseRequestHandlerclass EchoHandler(BaseRequestHandler):def handle(self) -> None:    print(f"Got connection from address {self.client_address}")self.request: socket.socketwhile True:msg = self.request.recv(2048)print(f"Message from client: \n{msg}")self.request.send(msg)if __name__ == '__main__':server = TCPServer(("", 12345), EchoHandler)       # TCPServer中实现了TCP服务器中的bind、listen和close等基本初始化操作server.serve_forever()

client:

# -*- coding:utf-8 -*-
import socket
import timedef connection():s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect(("localhost", 12345))while True:msg = input("Input msg and send:\n")s.send(msg.encode())print(f"Msg sent")time.sleep(1)if __name__ == '__main__':connection()

开启server服务之后,在client发送信息

# client
Input msg and send:
a
Msg sent
b
Msg sent
Input msg and send:
# server
Got connection from address ('127.0.0.1', 36087)
Message from client: 
b'a'
Message from client: 
b'b'

这个服务默认一次只能服务一个客户端,如果你尝试再打开一个client进程连接server时,发送消息后server端并不会立马收到消息,而是要等到第一个连接的client断开之后才会收到第二个client发送的消息,而且发送的多条消息会聚集到一条一种
服务端断开后才收到第二个client的消息

让服务器支持同时处理多个客户端

如果想要一个服务器能同时处理和服务多个客户端,可以初始化一个ForkingTCPServerThreadingTCPServer

if __name__ == '__main__':# server = TCPServer(("", 12345), EchoHandler)       # TCPServer中实现了TCP服务器中的bind、listen和close等基本初始化操作server = ThreadingTCPServer(("", 12345), EchoHandler)server.serve_forever()

然后client开启两个进程连接server并发送消息:
client开启两个进程分别连接server并发送消息

限制客户端连接数

但是随着客户端的数量增加,非常有必要限制一下客户端连接的数量和缩短连接等待时间,在linux上可以使用iptable限制连接数和sysctl限制TIME_WAIT时间
限制一个IP最多15个连接:

-A INPUT -p tcp -m tcp --dport 12345 --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 15 --connlimit-mask 32 --connlimit-saddr -j REJECT --reject-with tcp-reset

TCP连接超时时间设置为15s:

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

也可以使用多线程开启多个TCPServer的方式来实现支持处理多个客户端的情况:

if __name__ == '__main__':from threading import Threadserver = ThreadingTCPServer(("", 12345), EchoHandler, bind_and_activate=False)# 预先分配好最大的工作线程池,每个服务处理一个连接并限制了客户端连接的最大数量nworkers = 10for i in range(nworkers):t = Thread(target=server.serve_forever)t.daemon = Truet.start()server.serve_forever()

socket的一些常用选项

允许socket的bind方法重复使用local address

if __name__ == '__main__':server = TCPServer(("", 12345), EchoHandler, bind_and_activate=False)# SOL_SOCKET指定选项类型/等级并设定SO_REUSEADDR的值为真指定该socket支持重复使用地址server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)server.server_bind()server.server_activate()server.serve_forever()

上面这个选项由于经常被使用到,它被放到TCPServerallow_reuse_address属性,因此使用TCPServer时可以直接修改socket重复使用local address的选项:

if __name__ == '__main__':ThreadingTCPServer.allow_reuse_address = Trueserver = ThreadingTCPServer(("", 12345), EchoHandler)server.serve_forever()

ref: Understanding Socket Concept

ref: IP Family

ref: Socket types

ref: Socket Level options

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Pytorch神经网络理论篇】 09 神经网络模块中的损失函数

同学你好!本文章于2021年末编写,获得广泛的好评! 故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现, Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络理论篇】 10 优化器模块+退化学习率

同学你好!本文章于2021年末编写,获得广泛的好评! 故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现, Pytorch深度学习理论篇(2023版)目录地址…

HAProxy负载均衡原理及企业级实例部署haproxy集群

HAProxy是一种高效、可靠、免费的高可用及负载均衡解决方案,非常适合于高负载站点的七层数据请求。客户端通过HAProxy代理服务器获得站点页面,而代理服务器收到客户请求后根据负载均衡的规则将请求数据转发给后端真实服务器。 同一客户端访问服务器&…

【Pytorch神经网络实战案例】07 预测泰坦尼克号上生存的乘客

1 样本处理 1.1 载入样本代码---Titanic forecast.py(第1部分) import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from scipy import stats import pandas as pd import matplotlib.pyplot as plt import os o…

基于sanic的服务使用celery完成动态修改定时任务

首先声明一下 考虑到celery目前和asyncio的不兼容性,协程任务需要转换为非异步的普通方法才能被当做task加入定时,并且celery和asyncio使用可能会带来预想不到的问题,在celery官方第二次承诺的6.0版本融合asyncio之前,需要慎重考虑…

Pyscript,使用Python编写前端脚本

介绍 Anaconda的CEO Peter Wang在前两个月的时候发布了Pyscript,实现了在HTML支持Python的使用,整个引用过程甚至不需要安装任何环境,只需要使用link和script标签即可引用实现Python在HTML中运行的功能,在HTML中也可以运行和使用…

如何把应用程序app编译进android系统

转载:http://ywxiao66.blog.163.com/blog/static/175482055201152710441106/------------------------------------------------------------------把常用的应用程序编译到img文件中,就成了系统的一部分,用户不必自己安装,当然也卸…

【Pytorch神经网络实战案例】08 识别黑白图中的服装图案(Fashion-MNIST)

1 Fashion-MNIST简介 FashionMNIST 是一个替代 MNIST 手写数字集 的图像数据集。 它是由 Zalando(一家德国的时尚科技公司)旗下的研究部门提供。其涵盖了来自 10 种类别的共 7 万个不同商品的正面图片。 FashionMNIST 的大小、格式和训练集/测试集划分与…

PHP list的赋值

List右边的赋值对象是一个以数值为索引的数组,左边的变量的位置和赋值对象的键值一一对应,有些位置的变量可以省略不写。非末尾的被赋值变量省略时,分隔的逗号不能省略。左边变量被赋值的顺序是从右到左的。 1 list($a, ,$b,$c[],$c[]) [1,2…

Pyscript,创建一个能执行crud操作的网页应用

目录 实现一个添加邀请客人名单的功能 循序渐进,逐步实现: 输入客人名称,按下enter键添加客人名单点击客人名单在名单上添加或者取消添加删除线,表示已经检查客人到场或未到场 checkbox,点击客人名单或者点击checkb…

爬虫实战学习笔记_1 爬虫基础+HTTP原理

1 爬虫简介 网络爬虫(又被称作网络蜘蛛、网络机器人,在某些社区中也经常被称为网页追逐者)可以按照指定的规则(网络爬虫的算法)自动浏览或抓取网络中的信息。 1.1 Web网页存在方式 表层网页指的是不需要提交表单,使…

爬虫实战学习笔记_2 网络请求urllib模块+设置请求头+Cookie+模拟登陆

1 urllib模块 1.1 urllib模块简介 Python3中将urib与urllib2模块的功能组合,并且命名为urllib。Python3中的urllib模块中包含多个功能的子模块,具体内容如下。 urllib.request:用于实现基本HTTP请求的模块。urlb.error:异常处理…

java----IO和NIO的区别

概念:NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO&#xf…

【Pytorch神经网络理论篇】 11 卷积网络模型+Sobel算子原理

同学你好!本文章于2021年末编写,已与实际存在较大的偏差! 故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现, Pytorch深度学习理论篇(2023版)…

DataFrame高效处理行列数据/倒三角型数据/处理阶梯型数据/根据列的值确定行的值

锲子 在使用pandas处理数据时,遇到了一种要按照留存天数来处理的数据,当列所对应的日期超过了最晚的“今天”那么数据就要置为0,举个例子: 在这个DataFrame中,需要将超过了今天2022-10-30的数据置为“-”&#xff0c…

Sanic服务启动失败,报错Cannot finalize with no routes defined

Sanic服务启动失败,记录解决方法 问题描述 Sanic服务启动失败,同样的代码和python版本在之前的win10系统上运行的好好的,换了台win11的机器就跑不起来了,不知道是系统原因还是因为换了执行pycharm等其他原因 在尝试启动时总是会…

【Pytorch神经网络理论篇】 12 卷积神经网络实现+卷积计算的图解

同学你好!本文章于2021年末编写,获得广泛的好评! 故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现, Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络实战案例】09 使用卷积提取图片的轮廓信息(手动模拟Sobel算子)

1 载入图片并显示 import matplotlib.pyplot as plt import matplotlib.image as mpimg import torch import torchvision.transforms as transforms import os os.environ["KMP_DUPLICATE_LIB_OK"]"TRUE" ### 1 载入图片并显示 myimg mpimg.imread(img.…

【Pytorch神经网络理论篇】 13 深层卷积神经网络介绍+池化操作+深层卷积神经网络实战

同学你好!本文章于2021年末编写,获得广泛的好评! 故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现, Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络实战案例】10 搭建深度卷积神经网络

识别黑白图中的服装图案(Fashion-MNIST)https://blog.csdn.net/qq_39237205/article/details/123379997基于上述代码修改模型的组成 1 修改myConNet模型 1.1.1 修改阐述 将模型中的两个全连接层,变为全局平均池化层。 1.1.2 修改结果 ### 1.5 定义模型类 class m…