IPython下的网络协议学习-------以echo回显程序为例

在进入正文之前强烈推荐IPython 来学习网络编程,和C语言繁琐的语法和编译相比,IPython交互的输入输出效率奇高,打开两个IPython页面就可以方便的编写服务端和客户端程序了。推荐anaconda环境,集成了很多必备的库,以及IPython notebook 。

废话说完了,下面进入正题。本文主要以简单的回显程序为例,实践测试了不同异常情况下服务端和客户端的反应,由此逐步提高程序的健壮性。异常情况主要参考网络编程著作《UNIX网络编程》第三版。

我的服务器代码和客户端代码是这样的:

#Echo Server
import socket
import sys
import signal
import os
def server_echo(connefd):
    while 1:
        try :
            print ("before recv")
            mesg = connefd.recv(8)
            print (mesg)
            if not mesg:
                return
            connefd.send(mesg)
        except os.error:
            print ("socket error")      
            return 


def signal_handlers(signo,frame): #信号处理函数
    print ("child %d terminnated",os.wait())

serverPort = 50000
listenfd = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
listenfd.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
listenfd.bind(("",serverPort))
listenfd.listen(5)
signal.signal(signal.SIGCHLD,signal_handlers)  
while 1:
    connefd,address = listenfd.accept()
    childpid = os.fork()
    if(childpid == 0):
        listenfd.close()
        server_echo(connefd)
        exit(0)
    connefd.close()


#客户端
import socket
connefd = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connefd.connect(('127.0.0.1',5000))
while 1:
    sentence = input("Enter your sentence:")
    if sentence == "":
            connefd.close()
            break
    connefd.send(sentence.encode())
    mesg = connefd.recv(8)
    print mesg

代码很简单,比较值得一提的是服务器程序中利用系统调用fork函数进行实现并发服务器。除此之外,必须提供一个SIGCHLD信号的处理程序。当子进程结束时,内核会自动发送SIGCHLD信号给父进程,默认处理方式是忽略。那么我们为什么要处理SIGCHLD信号呢?原因是如果不主动处理SIGCHLD会产生大量僵尸进程

一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)

因此,仅仅调用exit()不能完全的释放进程资源,我们必须**捕捉(capture)**SIGCHLD信号,在父进程的信号处理程序中释放资源。为此,Unix系统提供了wait,waitpid等函数获取子进程的终止状态,并释放其资源。那么wait和waitpid这些函数有什么作用呢?顾名思义,wait函数是一个等待的函数,父进程调用wait函数来等待一个子进程终止,并清理第一个终止子进程的“尸体”。那么waitpid函数的作用又是什么呢?waitpid函数相当于一个加强版的wait函数,他的函数参数中可以设定需要等待的子进程ID,如果没有子进程已终止则可选择不阻塞等选项。参阅UNPV1第三版可以了解waitpid更详细的信息。

接下来就UNP 5.11节 至 5.16节的小节所述的异常情况进行模拟,并总结一些异常处理方法和编程技巧。

(1) 服务器程序在accept返回前连接终止

accept函数是服务器程序调用的一个函数,作用是服务器接受一个ESTABLISHED状态的TCP连接,并生成一个新的套接字,叫做已连接套接字(connected socket) 。函数接受的套接字是由listening socket 维护的 已连接队列中的队首的连接,如果队列为空,则accept函数阻塞。
注意:TCP连接在客户端调用connect函数返回时就已经完成连接,这意味着服务端在调用 accept函数之前TCP连接已经建立。

为了模拟accept函数在返回前连接终止,我们可以让客户端在connect函数返回后,利用SO_LINGER套接字选项来改变close函数的行为(让其向服务端发送RST报文段)。在RST报文段发送之前,我们的服务端accept函数应该返回。因此可以在服务端调用accept函数前利用input函数或是sleep函数阻塞程序,当RST报文端发送后再调用accept函数。服务端和客户端代码改变如下:

#服务端
while 1:
    input("Enter Any key to continue")  #添加的阻塞语句
    connefd,address = listenfd.accept()
#客户端:
connefd.connect(('127.0.0.1',5000))
connefd.setsockopt(socket.SOL_SOCKET,
                    socket.SO_LINGER,struct.pack("ii",True,0))#添加的套接字选项,改变了套接字close函数的执行内容,关于SO_LINGER套接字选项可以查阅UNP7.5节
connefd.close()

让我们运行代码测试一下结果,同时可以利用tcpdump或者是Wireshark抓包工具监测RST报文段是否发送成功。
客户端代码执行时的Wireshark抓包截图
客户端代码执行时的Wireshark抓包截图

最后让我们来看一下服务端收到RST报文段后服务端的响应。

ConnectionResetError                      Traceback (most recent call last)
<ipython-input-1-4ac06058bc37> in <module>()
     32     if(childpid == 0):
     33         listenfd.close()
---> 34         server_echo(connefd)
     35         os._exit(0)
     36     connefd.close()

<ipython-input-1-4ac06058bc37> in server_echo(connefd)
      8       #  try :
      9         print ("before recv")
---> 10         mesg = connefd.recv(8)
     11         print (mesg)
     12         if not mesg:

ConnectionResetError: [Errno 104] Connection reset by peer

​

可以看到服务端返回一个ConnectionResetError错误,而且继续调用accept函数,之后其他客户端也能继续连接服务端正常运行程序。我们也能捕捉ConnectionResetError,进而实现自定义的错误处理方法。

后续将继续对不同异常情况进行试验,记录学习TCP/IP协议的过程与经验。

W.Richard Stevens.UNIX网络编程 卷1:套接字联网API[M].北京:人民邮电出版社,2010

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值