~~网络编程(四):socket套接字~~

进击のpython


网络编程——socket


socket的中文意思叫做套接字,socket方法其实也叫套接字方法

我们研究过TCP/UDP协议,但是要是让我们自己搭建,就十分困难了

而这时候,socket就出来了

socket他是存在在应用层和传输层之间的一堆接口

他把复杂的协议都封装好了,你想用的时候,直接调用就行

就跟我们写模块一样,把麻烦的代码写进去,等到用的时候只需要调用就行了

那你想想,咱们在研究模块的时候,是不是学会方法怎么用就行??

那咱们学套接字方法,也是学会方法就行


我要是想给你打电话的话应该是怎么个过程?

# 首先我得有电话
# 输入想打的电话
# 等待你接听
# 跟你bb两句
# 听你bb两句

那你接电话呢?

# 首先你得有电话
# 你还得有电话号码
# 然后你得有电话线
# 等着接电话
# 铃响接电话
# 听你bb两句

没问题吧!

那我要是想写成socket通信呢?


首先我得先创建两个py文件是吧,通信嘛,当然要两个:客户端和服务端

然后要在两个文件都调用socket模块是吧

1433227-20190806112946890-2144354372.png

接下来就继续吧!

1433227-20190806113309330-991393939.png

解释一下啊,socket里面的两个属性,第一个是套接字的类型,我们这个是基于网络的嘛,所以是AF_INET

第二个是你数据的传输方式,SOCK_STREAM是流式传输,也就是TCP协议

1433227-20190806120809920-852200081.png

在这我们要学习一个方法 bind 绑定,因为是手机绑定,所以是phone.bind

里面要添加一个元组参数 IP 和 端口

其中ip 我设置的是127.0.0.1,代表着本机的意思,我这不是要在自己电脑上操作嘛

端口最大到65535 其中,1-1024 是系统的端口,1024之后的就是应用的了,你随便选个就行

1433227-20190806120338588-204553590.png

这里就是又一个方法了 listen 监听

里面要传一个参数,这个5是什么意思呢?

我这个电话接通的时候,别人又给我打电话,我也不能挂了啊

那这种状态可以维持几个手机同时给我打电话呢?5个

1433227-20190806120929927-498641251.png

那最后,我就开始等电话了是吧


那客户端呢?是不是要买手机啊我用绑定ip嘛?

换句话说我用手机绑定手机卡,说只能用这个手机的这张卡才能给你打电话???

这显然不对啊,所以,客户端不用绑定

客户端的拨号,用到了connet方法,里面放一个元组参数,元组由服务端的ip和端口构成

那我要是运行,是不是应该先运行服务端,再运行客户端.这个能理解吧

那我们执行一下

1433227-20190806122755748-379885493.png

看到了吧,这就算是连接上了,那我们看看我们拿的是什么东西

(<socket.socket fd=484, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 52621)>, ('127.0.0.1', 52621))

首先可以肯定这是个元组是吧,第一个元素是个什么东西?是不是套接字对象啊

第二个元素呢?是不是客户端的ip以及端口信息啊

那我们是不是可以通过解构的方式把这两个信息拿到啊

connet, client_addr = phone.accept()

那你说我这是不是就算是拿到了管道啊,那我有了管道了,我是不是就可以进行传输了啊


那我就可以收信息了,怎么收?又用到一个方法recv

connet.recv(1024)

它里面要传个参数,传接受的最大字节数

你给我传一个,我就收一个,你要是给我传1025个,我也收1024个

至于为什么是1024呢?我们后面说,你现在就先这么写

那我要是发消息呢?send方法

connet.send()

里面传发送的东西

打完电话就该挂电话了对吧

connet.close()

挂完电话是不是就关机了啊

phone.close()

那服务端完事了,客户端是不是也应该写点什么了

服务端是接收-发送

那我客户端是不是应该是发送-接收

客户端发送怎么写?send

phone.send("hello".encode("utf-8"))

别忘了把编码缀上

接收呢??recv

k = phone.recv(1024)
print(k)

然后呢?关机!

phone.close()

行啦!我们来看看写完的长什么样

1433227-20190806130144388-1435710559.png

执行一下吧(别忘了先执行服务端,再执行客户端)

1433227-20190806130300877-220718186.png

这样,就完成了一个简单的C/S结构!

话不多说,自己多敲几遍


正常人谁那么搞啊,不都是有来言有去语的吗

那我们是不是就应该用循环来搞这个需求

循环放在哪呢?我们不是要循环收发这个过程嘛

那我们就应该循环收发信息这一块的代码啊

# 服务端
import socket

# 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定手机卡
phone.bind(("127.0.0.1", 8080))

# 开机
phone.listen(5)

# 等电话
connet, client_addr = phone.accept()

# 收发消息
while 1:
    k = connet.recv(1024)
    print(f'从客户端接收的消息:{k}')
    connet.send(k.upper())

# 挂电话
connet.close()

# 关机
phone.close()
# 客户端
import socket

# 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 拨号
phone.connect(("127.0.0.1", 8080))

# 发收信息
while 1:
    msg = input(">>>")
    phone.send(msg.encode("utf-8"))
    k = phone.recv(1024)
    print(f"从服务端接收的消息:{k}")

# 关闭
phone.close()
# 服务端
从客户端接收的消息:b'as'
从客户端接收的消息:b'ds'
从客户端接收的消息:b'fa'

# 客户端
>>>as
从服务端接收的消息:b'AS'
>>>ds
从服务端接收的消息:b'DS'
>>>fa
从服务端接收的消息:b'FA'
>>>

还有一点就是想说,你们在调试的时候没遇到这个报错吗?

OSError:[Errno 48] Address already in use

这个问题就是说你刚关那个程序,然后系统还没有把你定义的端口给回收,你就又用了,就会出这个错误

怎么解决呢?

一种办法是修改客户端和服务端的端口,但是你不觉得太傻逼了吗?

所以还有另一种方法,就是在程序服务端绑定ip和端口下面添加一段这个代码

phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

这样就没事了,这个就是如果我发现这个端口被占用了,我就重新启用他


不是,那你们没有遇到bug嘛?

比如我在服务端直接敲回车,结果是什么???

你会发现你的程序执行不了了

那是谁的问题呢?是没发过去还是没接过来呢?

我们在send的下面写一个打印,发现可以被打印,那就说明我发过去了

而当我在接收的下面写一个打印,发现没有被打印,说明我没有接受到

而且服务端也没有执行原来有的print

那就说明是我发过去了,但是他什么都没有接收,所以她始终都在接受的这个位置等我传

也就是说空字符串是没办法单独传过去的,怎么解决这个问题呢?加个判断就好了啊

if not msg:continue

这样bug就没了


还有问题!你在断开客户端的时候,你会发现,服务端报错了!

ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

这是我们不能忍的啊,我不跟你链接了,你就报错?这不符合常识

所以我们就可以用异常捕获来处理

 try:
        k = connet.recv(1024)
        print(f'从客户端接收的消息:{k}')
        connet.send(k.upper())
    except ConnectionResetError:
        break

这样就没问题了!

这里多说一句啊,我这个代码是在windows里运行的,如果你是linux运行的

服务端是不会报错的,他会不停的接收一个空,一直循环不报错

这样就会使程序变成死循环!,这是我们所不能接受的!

所以,在服务端加个判断

if not k:break

这样就万无一失了!

毕竟正常人不会发送个空过来!


*有点东西*
*继续深究*

转载于:https://www.cnblogs.com/jevious/p/11308266.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值