zoukankan      html  css  js  c++  java
  • python网络编程学习笔记(3):socket网络服务器

    python网络编程学习笔记(3):socket网络服务器 - 小五义 - 博客园

    python网络编程学习笔记(3):socket网络服务器

    转载请注明:@小五义 http://www.cnblogs.com/xiaowuyi

            服务器和客户端程序很类似,上节学习了客户端程序,这一节将仔细学习一下利用socket建立TCP服务器和UDP服务器。

    1TCP连接的建立方法

     

            客户端在建立一个TCP连接时一般需要两步,而服务器的这个过程需要四步,具体见下面的比较。

    步骤TCP客户端TCP服务器
    第一步建立socket对象 建立socket对象
    第二步调用connect()建立一个和服务器的连接设置socket选项(可选)
    第三步绑定到一个端口(也可以是一个指定的网卡)
    第四步侦听连接

     

    下面具体来讲这四步的建立方法:

    第一步,建立socket对象:这里与客户端一样,依然是:

    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    第二步,设置和得到socket选项

    python定义了setsockopt()getsockopt(),一个是设置选项,一个是得到设置。这里主要使用setsockopt(),具体结构如下:

    setsockopt(level,optname,value)

    level定义了哪个选项将被使用。通常情况下是SOL_SOCKET,意思是正在使用的socket选项。它还可以通过设置一个特殊协议号码来设置协议选项,然而对于一个给定的操作系统,大多数协议选项都是明确的,所以为了简便,它们很少用于为移动设备设计的应用程序。

    optname参数提供使用的特殊选项。关于可用选项的设置,会因为操作系统的不同而有少许不同。如果level选定了SOL_SOCKET,那么一些常用的选项见下表:

    选项

    意义

    期望值

    SO_BINDTODEVICE

    可以使socket只在某个特殊的网络接口(网卡)有效。也许不能是移动便携设备

    一个字符串给出设备的名称或者一个空字符串返回默认值

    SO_BROADCAST

    允许广播地址发送和接收信息包。只对UDP有效。如何发送和接收广播信息包

    布尔型整数

    SO_DONTROUTE

    禁止通过路由器和网关往外发送信息包。这主要是为了安全而用在以太网上UDP通信的一种方法。不管目的地址使用什么IP地址,都可以防止数据离开本地网络

    布尔型整数

    SO_KEEPALIVE

    可以使TCP通信的信息包保持连续性。这些信息包可以在没有信息传输的时候,使通信的双方确定连接是保持的

    布尔型整数

    SO_OOBINLINE

    可以把收到的不正常数据看成是正常的数据,也就是说会通过一个标准的对recv()的调用来接收这些数据

    布尔型整数

    SO_REUSEADDR

    socket关闭后,本地端用于该socket的端口号立刻就可以被重用。通常来说,只有经过系统定义一段时间后,才能被重用。

    布尔型整数

     

    本节在学习时,用到了SO_REUSEADDR选项,具体写法是:

    S.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 这里value设置为1,表示将SO_REUSEADDR标记为TRUE,操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口。

    下面的方法可以帮助给出该系统下python所支持的socket选项列表:

    复制代码
    import socket
    
    solist=[x for x in dir(socket) if x.startswith('SO_')]
    
    solist.sort()
    
    for x in solist:
    
        Print x
    复制代码

    第三步:绑定socket

    绑定即为服务器要求一个端口号。

    S.bind((host,port)),其中host为服务器ip,通常为空,也可以绑定到一个特定的ip地址。Port为端口号。

    第四步:侦听连接。

    利用listen()函数进行侦听连接。该函数只有一个参数,其指明了在服务器实际处理连接的时候,允许有多少个未决(等待)的连接在队列中等待。作为一个约定,很多人设置为5。如:s.listen(5)

    2、简单的TCP服务器实例

            这个建立一个简单的TCP服务器和客户端。

    服务器端:TCP响应服务器,当与客户端建立连接后,服务器显示客户端ip和端口,同时将接收的客户端信息和'I get it!'传给客户端,此时等待输入一个新的信息传给客户端。

    客户端:TCP客户端,首先输入服务器ip地址,然后输入信息,回车后会得到服务器返回信息,然后等待服务器向其发送信息后退出。

    具体代码如下:

    服务器端:tcpserver.py

    复制代码
    # -*- coding: cp936 -*-
    ##tcp响应服务器,当与客户端建立连接后,服务器显示客户端ip和端口,同时将接收的客户端信息和'I get it!'传给客户端,此时等待输入一个新的信息传给客户端。
    ##@小五义 http://www.cnblogs.com/xiaowuyi
    import socket,traceback
    host=''
    port=12345
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    s.bind((host,port))
    s.listen(1)
    
    while 1:
        try:
            clientsock,clientaddr=s.accept()
        except KeyboardInterrupt:
            raise
        except:
            traceback.print_exc()
            continue
        try:
            print "连接来自:",clientsock.getpeername()
            while 1:
                data=clientsock.recv(4096)
                if not len(data):
                    break
                print clientsock.getpeername()[0]+':'+str(data)
                clientsock.sendall(data)
                clientsock.sendall("\nI get it!\n")
                t=raw_input('input the word:')
                clientsock.sendall(t)
        except (KeyboardInterrupt,SystemExit):
            raise
        except:
            traceback.print_exc()
    
        try:
            clientsock.close()
        except KeyboardInterrupt:
            raise
        except:
            traceback.print_exc()
    复制代码

    客户端:tcpclient.py

    复制代码
    # -*- coding: cp936 -*-
    ##tcp客户端,首先输入服务器ip地址,然后输入信息,回车后会得到服务器返回信息,然后等待服务器向其发送信息后退出。
    ##@小五义 http://www.cnblogs.com/xiaowuyi
    import socket,sys
    port=12345
    host=raw_input('输入服务器ip:')
    data=raw_input('输入要发送的信息:')
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    try:
        s.connect((host,port))
    except:
        print '连接错误!'
    s.send(data)
    s.shutdown(1)
    print '发送完成。'
    while 1:
        buf=s.recv(4096)
        if not len(buf):
            break
        sys.stdout.write(buf)
        
    复制代码

    执行结果:

    客户端输入hello,服务器端输入ok,具体显示结果是:

    服务器端:

    连接来自:('127.0.0.1',1945)

    127.0.0.1:hello

    Input the world:ok

    客户端:

    输入服务器ip:127.0.0.1

    输入要发送的信息:hello

    发送完成。

    hello

    I get it!

    ok

    3、UDP服务器

        UDP服务器建立与TCP相类似,具体比较如下:

    步骤

    UDP

    TCP

    第一步

    建立socket对象

    建立socket对象

    第二步

    设置socket选项

    设置socket选项

    第三步

    绑定到一个端口

    绑定到一个端口

    第四步

    Recvfrom()

    侦听连接listen

    这里利用UDP建立一个时间服务器。

    代码如下:

    服务器端;serverudp.py

    复制代码
    # -*- coding: cp936 -*-
    ##UDP服务器端,客户端连接后,向其发送当前时间
    ##@小五义 http://www.cnblogs.com/xiaowuyi
    import socket,traceback,time,struct
    host=''
    port=12345
    s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    s.bind((host,port))
    
    while 1:
        try:
            message,address=s.recvfrom(8192)
            secs=int(time.time())
            reply=struct.pack("!I",secs)
            s.sendto(reply,address)
        except (KeyboardInterrupt,SystemExit):
            raise
        except:
            traceback.print_exc()
    复制代码

    客户端:clientudp.py

    复制代码
    # -*- coding: cp936 -*-
    ##udp客户端,向服务器发送一个空字符后,得到服务器返回时间
    ##@小五义 http://www.cnblogs.com/xiaowuyi
    import socket,sys,struct,time
    host=raw_input('输入服务器地址:')
    port=12345
    s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    s.sendto('',(host,port))
    print "等待回复……"
    buf=s.recvfrom(2048)[0]
    if len(buf)!=4:
        print "回复错误%d:%s"%(len(buf),buf)
        sys.exit(1)
    secs=struct.unpack("!I",buf)[0]
    print time.ctime(int(secs))
    复制代码

    运行结果:

    首先运行服务器端,然后运行客户端。

    C:\>python clientudp.py  ##clientudp.py程序存放在在c盘下

    输入服务器地址:127.0.0.1

    等待回复……

    Mon Aug 06 17:09:17 2012

  • 相关阅读:
    第三周:Filter 拦截用户请求部分代码分析
    Story Of Web Background
    XML的前景
    XML的工作原理和过程
    第二周:XML的定义和用途
    企业级应用与互联网应用的区别
    第一周:JavaEE——课程目标
    Java 容器小结
    使用java显示所有操作系统环境变量
    迭代器和Interator的常见用法
  • 原文地址:https://www.cnblogs.com/lexus/p/2845099.html
Copyright © 2011-2022 走看看