python网络学习笔记——socket模块使用记录

此文章记录了笔者学习python网络中socket模块的笔记。

建议初次学习socket的读者先读一遍socket模块主要函数的介绍。

socket模块的介绍可以参考笔者的前一篇关于socket官方文档的学习记录:python网络学习笔记——socket模块官方文档学习记录。

一个简单地socket客户端(TCP)代码

(如果不懂代码含义可以看我上篇文章)

import socket   #导入socket模块
port =80   #端口
host="www.baidu.com"   #主机地址
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #创建套接字
s.connect((host,port))   #套接字连接
#向网站发送请求,注意参数时byte类型。不能是str(python3.7)。
s.sendall(b'GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:keep-alive\r\n\r\n')  
while 1:
   #从网页接受1024bytes大小的数据
    buf=s.recv(1024)
   #在无数据是跳出循环
    if not len(buf):
        break
   #打印数据
    print(buf)

简单的一个客户端程序,但并不严谨。

如果用户给了一个不存在的主机地址或没有服务的端口地址,那么在套接字连接的过程中:s.connect((host,port))会产生socket.gaierror。对上述程序可以用sys模块中的exit函数和try关键字来完善。

将套接字连接改为:

try:
    s.connect((host,port))
except socket.gaierror as e:
    print(e)
    #退出程序
    sys.exit(1)

以上完善程序过程仅仅是一个引入。在使用网络模块时可能会产生各种各样的异常,在编程写程序时应尽量考虑到可能产生的异常与处理方法。其中try和except…as可能是我们调试时使用最多的工具了。

上述程序还有一个不方便的地方,就是数据呈现的方式。buf在每次循环得到的是一个1024字节的byte数据。byte数据在输出时难以进行格式化的操作,并且1024字节大小的设置也很容易打乱原数据的格式。而套接字对象的makefile方法可以解决该问题。

s.makefile(mode=‘r’, buffering=None, *, encoding=None, errors=None, newline=None):
返回与套接字关联的文件对象。返回的对象的具体类型取决于 makefile() 的参数。这些参数的解释方式与内置的 open() 函数相同,其中 mode 的值仅支持 ‘r’ (默认),‘w’ 和 ‘b’。

makefile方法将byte操作转化为文件操作,这对数据的格式化操作提供了很大的便利。

所以,上述打印数据代码都可以换为以下内容(建议找一个源码比较少的网页进行尝试):
f

d=s.makefile(mode='rb')   #一定是rb,因为数据是byte类型
for i in fd.readlines():   #遍历
    print(i)

如果网页的源码过大的话,在打印过程中可能卡住。笔者在仅运行print(type(fd.readlines()))的情况下,电脑还是在1分钟后给出结果。也可以使用fd.readline()进行第一行测试。

建立socket客户端需要两个步骤。首先建立socket对象,其次,将socket连接到远程服务器上。

在建立socket对象的时候,您需要告诉系统两件事情:通信类型协议家族。通信类型指明用什么协议来传输数据。协议的例子包括IPv4(当前的Intermet标准),IPv6(将来的Intermet.IPX/SPX(NerWare和AFP(Apple文件共享)。到目前为止,最通用的是IPv4;协议家族则定义数据如何被传输。协议家族一般是表示TCP通信的SOCKSTREAM或便是UDP的SOCK_DGRAM。

端口号

"端口"是英文port的意译,可以认为是设备与外界通讯交流的出口。我们通过浏览器浏览的网页一般是服务器的80端口。可自行百度常用端口地址。

UDP客户端(不常用)

在socket被建立时,协议家族选择SOCK_DGRAM。

UDP对数据的发送和接收没有足够的控制,在不调用connect方法时,可以通过sendto()方法和recvfrom()方法。

s.recvfrom(bufsize[, flags]): 从套接字接收数据。返回值是一对 (bytes, address),其中
bytes 是字节对象,表示接收到的数据,address 是发送端套接字的地址。

s.sendto(bytes, flags, address): 发送数据给套接字。本套接字不应连接到远程套接字,而应由 address
指定目标套接字。返回发送字节数。 基本服务器操作

基本服务器操作

简单服务器代码:

import socekt
host='' #空字符代表可以接受任何主机的连接
port=51423   #可以选择任何一个大于1024的端口
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)   #创建套接字
s.bind((host, port))   #套接字绑定
s.listen(1)   #监听host的port,参数1表示最对有1个连接等待程序处理。
print("Server is running")
while True:
    try:
        ##当有客户端连接时,accept()方法会返回两个信息,一个连接客户端的套接字和连接主机地址
        sock, addr = s.accept()   
        print(addr)   #打印地址
    except Exception as e:
        print(e)
    fd=sock.makefile(mode="rb')
    print(fd.readline())   #打印数据第一行
    fd.close()   #关闭文件关联
    sock.close()       #关闭客户端套接字

s.bind(address): 将套接字绑定到 address。套接字必须尚未绑定(套接字作为服务器时使用)。

s.listen([backlog]): 启动一个作为服务器的套接字,用于接受连接(监听,方法名很直观)。如果指定
backlog,则它最低为 0(小于 0 会被置为 0),它指定系统允许暂未 accept
的连接数,超过后将拒绝新连接。未指定则自动设为合理的默认值 (套接字作为服务器时使用)。

s.accept(): 接受一个连接。调用此方法的socket对象必须绑定到一个地址上并且监听连接。返回值是一个 (conn,
address) 对,其中 conn 是一个 新的套接字对象,用于在此连接上收发数据,address
是连接另一端的套接字所绑定的地址。(套接字作为服务器时使用)。

域名系统(DNS)

socket的域名函数主要有:

socket.gethostbyname(host):
host是一个字符串的网址,返回解析之后的ip地址。

>>> socket.gethostbyname("www.baidu.com")
'61.135.169.125'

socket.gethostname():
无参数,返回本机的主机名。

>>> socket.gethostname()
'HOST-TEST'  #已做处理

socket.gethostbyname_ex(hostname):
将主机名转换为 IPv4 地址格式的扩展接口。返回三元组 (hostname, aliaslist, ipaddrlist),其中 hostname 是响应给定 ip_address 的主要主机名,aliaslist 是相同地址的其他可用主机名的列表(可能为空),而 ipaddrlist 是 IPv4 地址列表,包含相同主机名、相同接口的不同地址(通常是一个地址,但不总是如此)。(一个ip可能对应多个域名,一个域名也可对应多个ip。)

>>> socket.gethostbyname_ex('www.baidu.com')
('www.a.shifen.com', ['www.baidu.com'], ['61.135.169.121', '61.135.169.125'])

注:

  • bind()函数的第一个参数为空时,意思为可以绑定多有接口和地址。在只希望一个特定的地址链接时,可以指定参数。
  • 对数据进行完整性检查,注意信息丢失情况的TCP更适合客户端。而在服务器端,UDP不需要考虑丢包情况,更加适合。
  • 死锁发生在当一个服务器和客户端同时往同一个连接上写东西和同时从一个连接上读的时候。在这些情况下,没有进程可以得到任何的数据。

总结:
以上只是套接字的基础使用。不过在使用python进行网络编程时,socket模块很少使用。python有更高级的网络模块。

ps.此专栏是笔者学习《python网络编程基础》的学习笔记。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值