zoukankan      html  css  js  c++  java
  • python基础网络编程--转

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:

    • 消息传递(管道、FIFO、消息队列)
    • 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
    • 共享内存(匿名的和具名的)
    • 远程过程调用(Solaris门和Sun RPC)

    但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

    使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX  BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说“一切皆socket”。


    网络通信就是两个进程在通信

    网络编程对所有开发语言都是一样的,Python也不例外。用Python进行网络编程,就是在Python程序本身这个进程内,连接别的服务器进程的通信端口进行通信。

       (1) IP、TCP和UDP
        当您编写socket应用程序的时候,您可以在使用TCP还是使用UDP之间做出选择。它们都有各自的优点和缺点。
        TCP是流协议,而UDP是数据报协议。换句话说,TCP在客户机和服务器之间建立持续的开放连接,在该连接的生命期内,字节可以通过该连接写出(并且保证顺序正确)。然而,通过 TCP 写出的字节没有内置的结构,所以需要高层协议在被传输的字节流内部分隔数据记录和字段。
        另一方面,UDP不需要在客户机和服务器之间建立连接,它只是在地址之间传输报文。UDP的一个很好特性在于它的包是自分隔的(self-delimiting),也就是一个数据报都准确地指出它的开始和结束位置。然而,UDP的一个可能的缺点在于,它不保证包将会按顺序到达,甚至根本就不保证。当然,建立在UDP之上的高层协议可能会提供握手和确认功能。
        对于理解TCP和UDP之间的区别来说,一个有用的类比就是电话呼叫和邮寄信件之间的区别。在呼叫者用铃声通知接收者,并且接收者拿起听筒之前,电话呼叫不是活动的。只要没有一方挂断,该电话信道就保持活动,但是在通话期间,他们可以自由地想说多少就说多少。来自任何一方的谈话都按临时的顺序发生。另一方面,当你发一封信的时候,邮局在投递时既不对接收方是否存在作任何保证,也不对信件投递将花多长时间做出有力保证。接收方可能按与信件的发送顺序不同的顺序接收不同的信件,并且发送方也可能在他们发送信件是交替地接收邮件。与(理想的)邮政服务不同,无法送达的信件总是被送到死信办公室处理,而不再返回给发送。

        (2)对等方、端口、名称和地址
        除了TCP和UDP协议以外,通信一方(客户机或者服务器)还需要知道的关于与之通信的对方机器的两件事情:IP地址或者端口。IP地址是一个32位的数据值,为了人们好记,一般用圆点分开的4组数字的形式来表示,比如:64.41.64.172。端口是一个16位的数据值,通常被简单地表示为一个小于65536的数字。大多数情况下,该值介于10到100的范围内。一个IP地址获取送到某台机器的一个数据包,而一个端口让机器决定将该数据包交给哪个进程/服务(如果有的话)。这种解释略显简单,但基本思路是正确的。
        上面的描述几乎都是正确的,但它也遗漏了一些东西。大多数时候,当人们考虑Internet主机(对等方)时,我们都不会记忆诸如64.41.64.172这样的数字,而是记忆诸如gnosis.cx这样的名称。为了找到与某个特定主机名称相关联的IP地址,一般都使用域名服务器(DNS),但是有时会首先使用本地查找(经常是通过/etc/hosts的内容)。对于本教程,我们将一般地假设有一个IP地址可用,不过下面讨论编写名称查找代码。

        (3)主机名称解析
        命令行实用程序nslookup可以被用来根据符号名称查找主机IP地址。实际上,许多常见的实用程序,比如ping或者网络配置工具,也会顺便做同样的事情。但是以编程方式做这样的事情很简单。

    ======================TCP/IP======================
    应用层: 它只负责产生相应格式的数据 ssh ftp nfs cifs dns http smtp pop3
    -----------------------------------
    传输层: 定义数据传输的两种模式:
    TCP(传输控制协议:面向连接,可靠的,效率相对不高)
    UDP(用户数据报协议:非面向连接,不可靠的,但效率高)
    -----------------------------------
    网络层: 连接不同的网络如以太网、令牌环网
    IP (路由,分片) 、ICMP、 IGMP
    ARP ( 地址解析协议,作用是将IP解析成MAC )
    -----------------------------------
    数据链路层: 以太网传输
    -----------------------------------
    物理层: 主要任务是规定各种传输介质和接口与传输信号相关的一些特性
    -----------------------------------



    TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

    TCP socket 由于在通向前需要建立连接,所以其模式较 UDP socket 负责些。

     

    UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。如图:




    UDP Socket图:

    UDP socket server 端代码在进行bind后,无需调用listen方法。

    TCP/IP协议族包括运输层、网络层、链路层,
    而socket所在位置如图,Socket是应用层与TCP/IP协议族通信的中间软件抽象层。


    Socket是什么

    socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
    说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    注意:其实socket也没有层的概念,它只是一个facade设计模式的应用,让编程变的更简单。是一个软件抽象层。在网络编程中,我们大量用的都是通过socket实现的。

    Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。

    http://images2015.cnblogs.com/blog/720333/201611/720333-20161126215744846-706023541.png

    TCP编程

    Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。
    TCP连接简图: 三次握手,数据传输,四次挥手

    socket中TCP的三次握手建立连接详解

    我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

    • 客户端向服务器发送一个SYN J
    • 服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
    • 客户端再想服务器发一个确认ACK K+1

    只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?请看下图:

    image

    图1、socket中发送的TCP三次握手

    从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

    总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。

    5、socket中TCP的四次握手释放连接详解

    上面介绍了socket中TCP的三次握手建立过程,及其涉及的socket函数。现在我们介绍socket中的四次握手释放连接的过程,请看下图:

    image

    图2、socket中发送的TCP四次握手

    图示过程如下:

    • 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
    • 另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
    • 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
    • 接收到这个FIN的源发送端TCP对它进行确认。

    这样每个方向上都有一个FIN和ACK。

    Python3 网络编程

    Python 提供了两个级别访问的网络服务。:

    • 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
    • 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

    什么是 Socket?

    Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。

    socket和file的区别:

    • file模块是针对某个指定文件进行【打开】【读写】【关闭】
    • socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

     

     服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。


    socket()函数

    Python 中,我们用 socket()函数来创建套接字,语法格式如下:

    1
    socket.socket([family[, type[, proto]]])

    参数

    • family: 套接字家族可以使AF_UNIX或者AF_INET
    • type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAMSOCK_DGRAM
    • protocol: 一般不填默认为0.

    简单实例

    服务端

    我们使用 socket 模块的 socket 函数来创建一个 socket 对象。socket 对象可以通过调用其他函数来设置一个 socket 服务。

    现在我们可以通过调用 bind(hostname, port) 函数来指定服务的 port(端口)

    接着,我们调用 socket 对象的 accept 方法。该方法等待客户端的连接,并返回 connection 对象,表示已连接到客户端。

    完整代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #!/usr/bin/python3
    # 文件名:server.py
     
    # 导入 socket、sys 模块
    import socket
    import sys
     
    # 创建 socket 对象
    serversocket = socket.socket(
                socket.AF_INET, socket.SOCK_STREAM)
     
    # 获取本地主机名
    host = socket.gethostname()
     
    port = 9999
     
    # 绑定端口
    serversocket.bind((host, port))
     
    # 设置最大连接数,超过后排队
    serversocket.listen(5)
     
    while True:
        # 建立客户端连接
        clientsocket,addr = serversocket.accept()     
     
        print("连接地址: %s" % str(addr))
         
        msg='欢迎访问python教程!'+ " "
        clientsocket.send(msg.encode('utf-8'))
        clientsocket.close()

    客户端

    接下来我们写一个简单的客户端实例连接到以上创建的服务。端口号为 12345。

    socket.connect(hosname, port ) 方法打开一个 TCP 连接到主机为 hostname 端口为 port 的服务商。连接后我们就可以从服务端后期数据,记住,操作完成后需要关闭连接。

    完整代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #!/usr/bin/python3
    # 文件名:client.py
     
    # 导入 socket、sys 模块
    import socket
    import sys
     
    # 创建 socket 对象
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
    # 获取本地主机名
    host = socket.gethostname()
     
    # 设置端口好
    port = 9999
     
    # 连接服务,指定主机和端口
    s.connect((host, port))
     
    # 接收小于 1024 字节的数据
    msg = s.recv(1024)
     
    s.close()
     
    print (msg.decode('utf-8'))

     先执行server端,然后打开client端就能看到结果

    客户端

    大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。

    举个例子,当我们在浏览器中访问新浪时,我们自己的计算机就是客户端,浏览器会主动向新浪的服务器发起连接。如果一切顺利,新浪的服务器接受了我们的连接,一个TCP连接就建立起来的,后面的通信就是发送网页内容了。

    所以,我们要创建一个基于TCP连接的Socket,可以这样做:

    1
    2
    3
    4
    5
    6
    7
    # 导入socket库:
    import socket
     
    # 创建一个socket:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接:
    s.connect(('www.sina.com.cn', 80))

    创建Socket时,AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6SOCK_STREAM指定使用面向流的TCP协议,这样,一个Socket对象就创建成功,但是还没有建立连接。

    客户端要主动发起TCP连接,必须知道服务器的IP地址和端口号。新浪网站的IP地址可以用域名www.sina.com.cn自动转换到IP地址,但是怎么知道新浪服务器的端口号呢?

    答案是作为服务器,提供什么样的服务,端口号就必须固定下来。由于我们想要访问网页,因此新浪提供网页服务的服务器必须把端口号固定在80端口,因为80端口是Web服务的标准端口。其他服务都有对应的标准端口号,例如SMTP服务是25端口,FTP服务是21端口,等等。端口号小于1024的是Internet标准服务的端口,端口号大于1024的,可以任意使用。

    因此,我们连接新浪服务器的代码如下:

    1
    s.connect(('www.sina.com.cn', 80))

    注意参数是一个tuple,包含地址和端口号。

    建立TCP连接后,我们就可以向新浪服务器发送请求,要求返回首页的内容:

    1
    2
    # 发送数据:
    s.send(b'GET / HTTP/1.1 Host: www.sina.com.cn Connection: close ')

    TCP连接创建的是双向通道,双方都可以同时给对方发数据。但是谁先发谁后发,怎么协调,要根据具体的协议来决定。例如,HTTP协议规定客户端必须先发请求给服务器,服务器收到后才发数据给客户端。

    发送的文本格式必须符合HTTP标准,如果格式没问题,接下来就可以接收新浪服务器返回的数据了:

    接收数据时,调用recv(max)方法,一次最多接收指定的字节数,因此,在一个while循环中反复接收,直到recv()返回空数据,表示接收完毕,退出循环。

    当我们接收完数据后,调用close()方法关闭Socket,这样,一次完整的网络通信就结束了:

    1
    2
    # 关闭连接:
    s.close()

    接收到的数据包括HTTP头和网页本身,我们只需要把HTTP头和网页分离一下,把HTTP头打印出来,网页内容保存到文件:

    1
    2
    3
    4
    5
    header, html = data.split(b' ', 1)
    print(header.decode('utf-8'))
    # 把接收的数据写入文件:
    with open('sina.html', 'wb') as f:
        f.write(html)

    现在,只需要在浏览器中打开这个sina.html文件,就可以看到新浪的首页了。

    服务器

    和客户端编程相比,服务器编程就要复杂一些。

    服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Socket连接了。

    所以,服务器会打开固定端口(比如80)监听,每来一个客户端连接,就创建该Socket连接。由于服务器会有大量来自客户端的连接,所以,服务器要能够区分一个Socket连接是和哪个客户端绑定的。一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket。

    但是服务器还需要同时响应多个客户端的请求,所以,每个连接都需要一个新的进程或者新的线程来处理,否则,服务器一次就只能服务一个客户端了。

    我们来编写一个简单的服务器程序,它接收客户端连接,把客户端发过来的字符串加上Hello再发回去。

    首先,创建一个基于IPv4和TCP协议的Socket:

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

    然后,我们要绑定监听的地址和端口。服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址。127.0.0.1是一个特殊的IP地址,表示本机地址,如果绑定到这个地址,客户端必须同时在本机运行才能连接,也就是说,外部的计算机无法连接进来。

    端口号需要预先指定。因为我们写的这个服务不是标准服务,所以用9999这个端口号。请注意,小于1024的端口号必须要有管理员权限才能绑定:

    1
    2
    # 监听端口:
    s.bind(('127.0.0.1', 9999))

    紧接着,调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量:

    1
    2
    s.listen(5)
    print('Waiting for connection...')

    接下来,服务器程序通过一个永久循环来接受来自客户端的连接,accept()会等待并返回一个客户端的连接:

    1
    2
    3
    4
    5
    6
    while True:
        # 接受一个新连接:
        sock, addr = s.accept()
        # 创建新线程来处理TCP连接:
        t = threading.Thread(target=tcplink, args=(sock, addr))
        t.start()

    每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def tcplink(sock, addr):
        print('Accept new connection from %s:%s...' % addr)
        sock.send(b'Welcome!')
        while True:
            data = sock.recv(1024)
            time.sleep(1)
            if not data or data.decode('utf-8') == 'exit':
                break
            sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
        sock.close()
        print('Connection from %s:%s closed.' % addr)

    连接建立后,服务器首先发一条欢迎消息,然后等待客户端数据,并加上Hello再发送给客户端。如果客户端发送了exit字符串,就直接关闭连接。

    要测试这个服务器程序,我们还需要编写一个客户端程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接:
    s.connect(('127.0.0.1', 9999))
    # 接收欢迎消息:
    print(s.recv(1024).decode('utf-8'))
    for data in [b'Michael', b'Tracy', b'Sarah']:
        # 发送数据:
        s.send(data)
        print(s.recv(1024).decode('utf-8'))
    s.send(b'exit')
    s.close()

    我们需要打开两个命令行窗口,一个运行服务器程序,另一个运行客户端程序,就可以看到效果了:

    UDP编程

    TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。

    使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。

    虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。

    我们来看看如何通过UDP协议传输数据。和TCP类似,使用UDP的通信双方也分为客户端和服务器。服务器首先需要绑定端口:

    1
    2
    3
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口:
    s.bind(('127.0.0.1', 9999))

    创建Socket时,SOCK_DGRAM指定了这个Socket的类型是UDP。绑定端口和TCP一样,但是不需要调用listen()方法,而是直接接收来自任何客户端的数据:

    1
    2
    3
    4
    5
    6
    print 'Bind UDP on 9999...'
    while True:
        # 接收数据:
        data, addr = s.recvfrom(1024)
        print 'Received from %s:%s.' % addr
        s.sendto('Hello, %s!' % data, addr)

    recvfrom()方法返回数据和客户端的地址与端口,这样,服务器收到数据后,直接调用sendto()就可以把数据用UDP发给客户端。

    注意这里省掉了多线程,因为这个例子很简单。

    客户端使用UDP时,首先仍然创建基于UDP的Socket,然后,不需要调用connect(),直接通过sendto()给服务器发数据:

    1
    2
    3
    4
    5
    6
    7
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for data in ['Michael', 'Tracy', 'Sarah']:
        # 发送数据:
        s.sendto(data, ('127.0.0.1', 9999))
        # 接收数据:
        print s.recv(1024)
    s.close()

    从服务器接收数据仍然调用recv()方法。

    小结

    UDP的使用与TCP类似,但是不需要建立连接。此外,服务器绑定UDP端口和TCP端口互不冲突,也就是说,UDP的9999端口与TCP的9999端口可以各自绑定。

    Python 提供了两个级别访问的网络服务。:

    • 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
    • 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

     

    Socket 对象(内建)方法

    函数描述
    服务器端套接字
    s.bind() 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
    s.listen() 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
    s.accept() 被动接受TCP客户端连接,(阻塞式)等待连接的到来
    客户端套接字
    s.connect() 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
    s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
    公共用途的套接字函数
    s.recv() 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
    s.send() 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。
    s.sendall() 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
    s.recvform() 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
    s.sendto() 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
    s.close() 关闭套接字
    s.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
    s.getsockname() 返回套接字自己的地址。通常是一个元组(ipaddr,port)
    s.setsockopt(level,optname,value) 设置给定套接字选项的值。
    s.getsockopt(level,optname[.buflen]) 返回套接字选项的值。
    s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
    s.gettimeout() 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
    s.fileno() 返回套接字的文件描述符。
    s.setblocking(flag) 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
    s.makefile() 创建一个与该套接字相关连的文件

     

    server端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    import socket
     
    ip_port = ('127.0.0.1',9999)
     
    sk = socket.socket()
    sk.bind(ip_port)
    sk.listen(5)
     
    while True:
        print 'server waiting...'
        conn,addr = sk.accept()
     
        client_data = conn.recv(1024)
        print client_data
        conn.sendall('不要回答,不要回答,不要回答')
     
        conn.close()
     
    socket server

     client:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import socket
    ip_port = ('127.0.0.1',9999)
     
    sk = socket.socket()
    sk.connect(ip_port)
     
    sk.sendall('请求占领地球')
     
    server_reply = sk.recv(1024)
    print server_reply
     
    sk.close()
     
    socket client

     WEB服务应用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #!/usr/bin/env python
    #coding:utf-8
    import socket
      
    def handle_request(client):
        buf = client.recv(1024)
        client.send("HTTP/1.1 200 OK ")
        client.send("Hello, World")
      
    def main():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost',8080))
        sock.listen(5)
      
        while True:
            connection, address = sock.accept()
            handle_request(connection)
            connection.close()
      
    if __name__ == '__main__':
      main()
  • 相关阅读:
    osu合集(期望dp)
    P1640 [SCOI2010]连续攻击游戏
    P2155 [SDOI2008]沙拉公主的困惑
    P3419 [POI2005]SAMToy Cars / SP688 SAM Toy Cars
    P3586 [POI2015]LOG
    P4147 玉蟾宫
    P4454 [CQOI2018]破解DH协议
    射击小游戏一02(玩家和怪物添加)
    ASCII,Unicode和UTF8
    Android中MenuInflater实例
  • 原文地址:https://www.cnblogs.com/nongchaoer/p/10252653.html
Copyright © 2011-2022 走看看