Python的的Socket编程过程中实现编程过程中实现UDP端口复用的实例分享端口复用的实例分享
关于端口复用关于端口复用
一个套接字不能同时绑定多个端口,如果客户端想绑定端口号,一定要调用发送信息函数之前绑定( bind )端口,因为在发送
信息函数( sendto, 或 write ),系统会自动给当前网络程序分配一个随机端口号,这相当于随机绑定了一个端口号,这里只会
分配一次,以后通信就以这个随机端口通信,我们再绑定端口号的话,就会绑定失败。如果我们放在发送信息函数( sendto,
或 write )之前绑定,那样程序将以我们绑定的端口号发送信息,不会再随机分配一个端口号。实际上,默认的情况下,如果一
个网络应用程序的一个套接字 绑定了一个端口,这时候,别的套接字就无法使用这个端口。那如何让两个套接字都能成功绑
定一个端口呢?这时候就需要要到端口复用了。端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。
端口复用能在系统已开放的端口上进行通讯,只对输入的信息进行字符匹配,不对网络数据进行任何拦截、复制类操作,所以
对网络数据的传输性能丝毫不受影响。
但要注意,建立连接后服务端程序占用极少系统资源,被控端不会在系统性能上有任何察觉,通常被后门木马所利用。
在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确
则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重
大的一个安全隐患。
Python解决解决UDP端口复用问题端口复用问题
一直觉得UDP协议很简单,但是今天问题让我感觉到网络的基础真是博大精深。
废话少说,来看问题吧。由于协议的需要,我得实现一个UDP的客户端和服务器端,并且从同一个端口读写数据。
最初不以为然,无非就是用两个socket,一个监听并从这个端口读取数据(服务器端采用了twisted),另一个向这个端口
写入数据,用python实现只要10行左右的代码。
def startServer(queue, port):
reactor.listenUDP(port, DhtResponseHandler(queue))
reactor.run()
def sendUdpMsg(self, addr, msg):
socketHandler = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socketHandler.bind(("", self.port))
socketHandler.sendto(msg, addr)
socketHandler.close()
由于要向同一个端口写数据,于是client必须有bind,但是运行后发现server先bind了这个端口,client运行时会报错
复制代码 代码如下:
error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
一般这种错误时因为多个socket不能同时bind同一个地址
由于基础不够扎实,我开始疯狂的搜索,发现有人说端口复用的问题,所谓的端口复用,是指一个套接字释放掉一个端口
后有一个wait_time,另一个套接字如果接着bind就会报错。虽然我的问题不完全一样,但是我欣喜若狂的使用了。即在client
bind前加上如下一句
socketHandler.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
但是仍然报错:
复制代码 代码如下:
error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions
(顺便一提,还有另一个参数叫SO_REUSEPORT,即复用端口,另外有一个叫SO_EXCLUSIVEADDRUSE,即不准复用
该端口,其他socket的参数还有很多,可以参考winsockhttp://msdn.microsoft.com/en-us/library/aa924071.aspx或者unix下的
socket)
这个10013错误让我百思不得其解,搜索一下,主要有两种解释,有人说是需要提升应用程序的权限为管理员,我用的是
eclipse+pydev,提升完eclipse权限没用,实际上还要修改python.exe的权限,方法是在这个程序上右键,兼容性一栏中勾上
以系统管理员身份运行;有人说是跟其他程序地址或者端口冲突。但是我测试过发现都不行。
另外,运行的时候发现,twisted的服务器端一定是要在主线程中,否则会报signal一定要在主线程才能接受的错误,但是
twisted的reactor一运行起来就阻塞了。
在twisted文档中翻到,原来还有一种UDP叫做connected UDP,变态吧,所谓connected UDP,就是只能向一个地址收发
数据,看起来貌似可以,但是不符合可以向多个地址接收数据。
最后在一篇文章中翻到说需要两个端口都设置重用,于是我试着重新写一个服务器,与之前的客户端配合,运行良好,完
全无错
评论0