博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
pythonl练习笔记——PythonNet 套接字socket
阅读量:6452 次
发布时间:2019-06-23

本文共 6153 字,大约阅读时间需要 20 分钟。

1 套接字socket

1.1 套接字概述

套接字,一种网络通讯工具;用于进行网络间的通信,是一种特殊文件类型,

套接字,是一个通信链的句柄,用于描述IP地址和端口,实现向网络发出请求或应答网络请求。

 

socket可以实现对文件的打开、读写和关闭模式操作,与file有相似之处

    file模块是针对某个指定文件进行打开、读写和关闭操作的;

    socket模块是对服务器和客户端socket进行打开、读写和关闭的操作。

1.2 套接字分类

流式套接字

按照字节流进行数据传输,提供面向连接的可靠的数据传输服务,TCP协议。

流式对数据来说是安全的,一次接受不完,下次还会继续接受。

数据报套接字

按照数据包进行数据的传输,提供无连接的不可靠的传输服务,UDP协议

原始套接字:底层套接字

注:

面向连接:在进行数据通信之前需要先建立服务端和客户端的连接,以确保消息传输的可靠性;不允许有数据的丢失的,一旦出现数据丢失,则认为数据不可靠,断开连接

面向无连接:数据发送前不需要确定连接关系,数据的发送是不可靠的,

1.3 TCP协议 (面向连接)

适用于: 传输质量要求高,数据传输量大,且需要可靠性

三次握手:

1.客户端向服务器端发起连接请求ack 

2.服务器收到请求后确认允许连接,返回给客户端

3.客户端确认可连接后告知服务器准备发送消息

四次挥手:

1. 主动方告知被动方要断开连接

2. 接受到主动方请求后告知主动方已经接受到请求

3. 接收端处理完网络消息等工作后再次告知主动端可以断开

4. 主动方完成连接的断开

以确保发出的消息不会出现残留,传输一半的情况

1.4 UDP协议(面向无连接)

适用于:对消息可靠型没有严格要求,需要传输效率,网络状态不佳

2 基于TCP流式套接字过程

2.1 TCP服务器

主要有6步

1 创建套接字

2 绑定服务器IP端口

3 将套接字变为监听套接字,使可以接受tcp连接

4. 准备接受客户端连接

5 收发消息

6 关闭套接字

2.1.1 创建套接字(流式套接字)

 socket(family = AF_INET,type = SOCK_STREAM,proto = 0) 

功能:创建一个套接字

参数:

family:地址族类型

            基于不同主机间的通信

             AF_INET   IPv4(默认)

            AF_INET6  IPv6 

            基于一台主机进程间的文件通讯

            AF_UNIX    只能够用于单一的Unix系统进程间通信

type:套接字类型

          SOCK_STREAM  流式套接字 TCP (默认)

          SOCK_DGRAM   数据报套接字 UDP

proto:与特定的地址家族相关的协议

           默认为0,此时系统就会根据地址格式和套接字类别,自动选择一个合适的协议

          一般选择默认值0

返回值 : 返回一个套接字对象

2.1.2 绑定服务器IP、端口

 sockfd.bind(address) 

功能:绑定服务器的IP和端口

参数:address是一个元组(hostname, port)),第一个为字符串类型IP,第二个为数字类型端口号

示例 sockfd.bind('0.0.0.0',8888) 

备注:socfkd为套接字句柄

2.3  监听套接字

 sockfd.listen(backlog) 

功能:开启TCP监听,创建监听队列,将套接字变为监听套接字。使其可以接受TCP连接

参数:backlog为正整数

备注:一个套接字可以连接很多客户端,不过瞬态只能连接一个(由于很快,所以无法模拟出来),处理完后再连接其他的;由于瞬态很快,所以可以理解为是一个队列。

2.1.4 准备接受客户端连接

 sockfd.accept() 

功能:阻塞等待客户端的连接,并一直处于等待状态

参数:无

返回值 :

         第一个是一个与客户端通信的新的套接字

         第二个是连接进来的客户端的地址

2.1.5 收发消息

 conn.recv(buffer) 

功能:接受消息

参数:buffer:表示一次从缓冲区接受内容的大小

返回值:接受到的消息

 conn.send() 

功能 : 发送消息

参数 : 要发送的消息

返回值 : 发送消息的大小

2.1.6 关闭套接字

 sockfd.close() 

2.2 TCP客户端

1 创建套接字

2 发起连接

3 收发消息

4 关闭套接字 

注意:在python3消息收发为byte,故遇到字符串需要编译

3 TCP套接字示例

套接字中的两个阻塞函数:

 recv 和 send 为阻塞函数,

当缓冲区满时,执行send函数时会阻塞;

当缓冲区空时,执行recv函数时会阻塞

如果连接断开则recv会马上返回空字符串,结束阻塞

 

telnet 可以测试TCP套接字讯号通断,而不能检测UDP信号的情况

3.1 创建TCP服务器

import socketHOST = '0.0.0.0'PROT = 8888ADDR = (HOST,PROT)# 指定 Socket 接收缓冲区的大小BUFFERSIZE = 1024# 创建套接字# 使用from socket import *全部导入后,可以直接去掉socket前缀sockfd = socket.socket(socket.AF_INET,socket.SOCK_STREAM)# 绑定服务器IP端口sockfd.bind(ADDR)# 将套接字变成监听套接字,使可以接受TCP连接sockfd.listen(5)# 准备接受客户端连接print("wait for connect")# conn 为一个与客户端通信的新的套接字# addr 为连接进来的客户端的地址conn,addr = sockfd.accept()print("connect from",addr)# 收发消息data = conn.recv(BUFFERSIZE)print(data.decode())# 发送消息num = conn.send("Receive your request".encode())print(num)# 关闭套接字conn.close()sockfd.close()# 在python3消息收发为byte,而上面均是字符串,所以需要编译

3.2 创建TCP客户端

from socket import *SERVER_HOST = '0.0.0.0'SERVER_PORT = 8888SERVER_ADDR = (SERVER_HOST,SERVER_PORT)# 创建TCP套接字# 同类型套接字可以连接,非同类套接字不可连接sockfd = socket(AF_INET,SOCK_STREAM)# 发起连接sockfd.connect(SERVER_ADDR)# 向服务器发送信息sockfd.send(b'hello server')# 接受服务器返回信息,缓冲区大小为1024data = sockfd.recv(1024)print(data)# 关闭套接字sockfd.close()

3.3 运行

(1)运行服务器

出现: wait for connect 

(2)运行客户端

此时客户端出现: b'Receive your request' 

同时服务器出现

connect from ('127.0.0.1', 57946)hello server20

 

注意事项:

(1)不能先运行客户端,否则会出现 ConnectionRefusedError 

Traceback (most recent call last):  File "t_c.py", line 12, in 
sockfd.connect(SERVER_ADDR)ConnectionRefusedError: [Errno 111] Connection refused

找不到服务器,无法运行代码。

(2)连续运行服务器时,会出现 Address already in use 

Traceback (most recent call last):  File "t_s.py", line 15, in 
sockfd.bind(ADDR)OSError: [Errno 98] Address already in use

连续运行服务器时,原端口尚没有释放,所以会出现 address 被占用情况。

解决方案:

(a)出现address被占用时,暂停一会再执行,等待端口从缓冲区释放

(b)再运行服务器前修改端口号: SERVER_PORT = 8888 比如改成9999等之类

(c) setsockopt(SOL_SOCKET,SO_REUSEADDR,1) ,将其设置为1,端口可重用,可以再重新启用。

4 沾包

沾包的定义:

在TCP流式套接字中,发送方发送的若干数据被接收方一次性接受,就好像一条数据一样粘连在一起,这种现象为数据沾包

(1)在文件传输过程中沾包是不需要处理的

(2)如果发送的每一条消息都有特定的意义,此时需要考虑沾包带来的影响

沾包的形成:

也即,粘包形成的必要条件,

(1)流式套接字

(2)接受的没有发送的快

沾包的解决:

解决沾包的方案:

(1)格式化数据

(2)发送数据时指明数据长度

(3)每次发送有一个时间间隔,一般而言,相隔0.1秒足够了,但该方法不适合数据量较大的、频繁发送的情况;该方法使用也较少。

4 数据报套接字UDP

4.1 关键字

 sockfd.recvfrom() 

功能:接受网络消息

参数:buffersize

返回值 :

data:接收到的消息

addr:消息来源的ADDRESS

每次recvfrom接受一个数据报,即使接受不全就会使其他数据丢失

 sockfd.sendto() 

功能:发送消息

参数:

data:要发送的消息

addr:将消息发送给谁

sendall() 和send()基本相同,试图发送所有消息,发送成功返回None,失败则报出异常

sendall()和sendto不一样,不能替代sendto

4.2 服务器(UDP数据报套接字)

(1)创建数据报套接字

(2)绑定IP和端口

(3)接受发送消息

(4)关闭套接字

 4.3 客户端(UDP数据报套接字)

与TCP数据流套接字类似。

5 UDP套接字示例

5.1 服务器(UDP)

from socket import *from time import *HOST = '127.0.0.1'PORT = 8888ADDR = (HOST,PORT)BUDDERSIZE = 1024# 创建数据报套接字sockfd = socket(AF_INET,SOCK_DGRAM)# 绑定IP端口sockfd.bind(ADDR)while True:    # 接受发送消息    data, addr = sockfd.recvfrom(BUDDERSIZE)    print('recv from ',addr)    # 发送消息    sockfd.sendto(('%s:[%s]'%(ctime(),data)).encode(),addr)# 关闭套接字sockfd.close()

5.2 客户端(UDP)

from socket import *import sys# sys.argv 从外设获取的迭代对象并返回列表# sys.argv[0]为路径# 少于三个元素则退出运行if len(sys.argv) <3:    print('argv is error')    sys.exit(1)# 获取IP地址HOST = sys.argv[1]#从终端获得的为字符串,需转换成整形PORT = int(sys.argv[2])ADDR = (HOST,PORT)BUFFERSIZE = 1024# 创建数据报套接字sockfd = socket(AF_INET,SOCK_DGRAM)while True:    data = input(">>")    if not data:        break    # 发送消息,第一元素为发送内容,ADDR为内容接受的地址    sockfd.sendto(b"hello udp server",ADDR)    data, addr = sockfd.recvfrom(BUFFERSIZE)    print(data.decode())# 关闭套接字sockfd.close()

5.3 运行

1 先运行服务器,实际上没有任何显示

2 运行客户端

注意:

(a)由于客户端 len(sys.argv) > 3 的限制,所以必须输入三个元素以上才不会使程序运行结束

(b)t_c.py、‘127.0.0.1’、‘8888’三个元素中间必须用空格隔开,如果连在一起则会认为一个元素

(c)IP(‘127.0.0.1’)和端口('8888')必须与服务器名称一致, 否则 sockfd.sendto(b"hello udp server",ADDR) 中的ADDR找不到服务器

3 向客户端中输入内容

6 sys.argv()

示例:文件名s_argv.py

import sysif len(sys.argv) <3:    print('argv is error')    sys.exit(1)print(sys.argv)print(sys.argv[1])print(sys.argv[2])

运行: python3 s_argv.py 

结果: argv is error 

因为 len(sys.argv) < 3  所以会直接结束 sys.exit(1) 

 

再运行结果

python3 s_argv.py '127.0.0.1' '8888'#直接显示结果['s_argv.py', '127.0.0.1', '8888']127.0.0.18888

 

再运行

python3 s_argv.py a 12['s_argv.py', 'a', '12']a12

详细信息可参考

7 TCP与UDP对比

UDP 比 TCP 更加适合提供循环服务

循环服务方式不适合传输时间过长,一个客户端需要长期占用服务器的情况,TCP连接则需要持续连接占用服务器。

8 套接字属性

套接字对象的属性

conn.getpeername() # 得到连接端的addrsockfd.getsockname() # 获取套接字对应主机的信息sockfd.type  # 测试套接字类型getsockopt(level,optname) # 获取值setsockopt(level,optname,value) # 设置值setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 让套接字端口可以重用,当套接字结束时,可以再重新启用

 

转载地址:http://fjgwo.baihongyu.com/

你可能感兴趣的文章
密码的校验.大小写字母,数字,特殊字符中的至少3种
查看>>
ios 不同sdk4.3 6.0版本号,关于方法的兼容性的通用方法
查看>>
Shell编程学习总结
查看>>
070、如何定制Calico 网络policy(2019-04-15 周一)
查看>>
构建之法阅读笔记02
查看>>
Webstorm常用快捷键备忘
查看>>
js滚动加载到底部
查看>>
关于mac远程链接window服务器以及实现共享文件
查看>>
Redis慢查询,redis-cli,redis-benchmark,info
查看>>
Virtualbox 虚拟机网络不通
查看>>
java概念基础笔记整理
查看>>
self parent $this关键字分析--PHP
查看>>
CC_UNUSED_PARAM 宏含义的解释
查看>>
leetcode124二叉树最大路径和
查看>>
AngularJS笔记整理 内置指令与自定义指令
查看>>
学习OpenCV——BOW特征提取函数(特征点篇)
查看>>
shell与正则表达式
查看>>
第三篇:白话tornado源码之请求来了
查看>>
10分钟搞定支付宝和微信支付的各种填坑
查看>>
表示数值的字符串
查看>>