这两天在练习用python写socket的小程序,浏览了挺多博客,感觉好像直接举例的多;基本没有人具体说socket编程应该遵守一个什么模式,如何在程序或者项目中使用,还有那些事情要注意的地方。
我觉得有可能有两点原因:
1、socket这个知识点大家可能都学过,所以大多数人都是把自己练习的例子贴出来,但是没有真正用在自己的项目中;
2、socket内容太多,真正用起来是属于比较底层的“基础设施”,在一些公司里可能都是用C语言或者更注重效率的方式实现的,这个知识点就变成不是大家关注的热点。
所以socket编程,可能是因为上手快,但是没有应用场景,所以看多了博文,觉得例子大同小异,对我的启发有限。
因为想多了解一些如何使用socket进行通讯,所以这两天由返回到官网上找到了这篇文章《Socket Programming HOWTO》。
说实话,当时看到这篇文章的时候,光看了个题目,觉得可能没啥东西,就用题目搜了一下,结果下载到一篇PDF。当时还是想找找中文的资料,就没注意PDF的内容。但是中文资料确实没啥我想要的信息,所以今天就有回头看这个PDF。
打开PDF,结果第一眼就看到了大牛的名字,说实话,这一下就让我不淡定了。虽然这篇文章的作者是:Gordon McMillan,但是有Guido名字作为背书,我选择好好看一看这个文章。
第一个知识点
多数client socket 只用于一次信息交换。
这个确实不是我之前理解的样子。我之前可能把socket当作类似session这样,能保持一种连接状态,持续不断的完成服务端和客户端的信息交互(当然也可以,不是说不行,只是文章中说一般只用来交互一次)。我就觉得这种情况下,要处理的异常场景太多了:服务端挂了怎么办,客户端怎么知道?客户端挂了,服务端怎么知道?一个socket挂了,怎么重新连?信息从什么地方开始重新传?这些问题不是无解,而是会因为这些问题导致通讯程序越写越大,越写越复杂。让人不安:处理这些异常的方式是否正确?是否还有哪些异常没有考虑?
但是如果一个client socket只用于一次交换,那么通讯这个场景就变得简化了:client socket建立一次连接,发送一次数据,搞定收工。其他还要信息的话,在来一次这样的连接,发送操作。这种方式确实简单了许多。
第二个知识点
socket完成连接后,可以有三种方式处理具体的通讯工作。
1、使用线程;
2、使用进程;
3、使用non-blocking模式,配合select这种系统调用的方式。
虽然作者没有具体举例子,但是他已经划出了三条道。一般人估计跳不出这三条道,这应该算是总结了具体通讯的三种模式。
第三知识点
我们用send和recv操作的是缓冲区,而不是具体的信息字节。
我的说法是有点不清楚,我就说一个例子。下午我在试验的时候,通过客户端在一个循环里给服务端发送了四次“nihao”,
for i in range(1,5)
clientSocket.send("nihao")
服务端收到了什么?直接一次收到了四个连在一起的“nihaonihaonihaonihao”,这个例子就说明,我发送时,send(),将信息发送到了缓冲区,recv也是通过缓冲区获取的信息。并不是按照我的想法,发一个nihao,收一个nihao。当然看到试验结果的时候能够猜到确实有缓冲,但是上面这段文字证实了对缓冲区理解,我觉得对未来编程还是是有帮助的。
第四个知识点
当另一端socket关闭时,这一端的socket调用recv 会返回0字节。
这也就大家常用来进行是否接收结束的的条件:
data = connSock.recv(1024)
if data:
# 打印数据
else:
connSocke.close()
收到0字节的信息,表示对方关闭了socket,我也就应该关闭socket了。
第五个知识点
处理信息时,一共也就三种方法:1、固定信息的长度;2、分割传递的信息;3、传递信息长度和信息。
对于第三种方式,文章还给出了建议:因为具体没有实践过,这个知识点就先记下来。
第六个知识点
关于二进制数,要进行字节序转换。
不过文章中说,ascii码表示信息比二进制表示信息短,这一点我没理解,也就先记下来。
第七个知识点
如果对端的socket挂了(没有调用close),怎么办?
实际上,对端的socket挂了(比如客户进程被干掉了),这一端的socket是无法知道的。线程只会挂起,要很久才会超时。但是不要想着去关闭线程,因为关闭线程可能会把整个进程搞得很乱。
那到底怎么办?好像没有说。我猜,可能是1、设置较短的超时时间,超时,就默认对方挂了。2、就是之前说的,一次连接,只做一次交换。这样就算异常了,也只影响一次交换的数据,上层程序应该控制,进行重传或者断点续传。
第八个知识点
非阻塞方式,配合select,检查各个socket的状态,那个可以读,那个可以写,是否需要建立新的连接。
这个还挺有趣,但是我真是第一次见,所以准备下去动手试一试。
以上对我来说,是八个挺重要的知识点。希望对你们也有用。