python 网络编程笔记

 学习路线:socket-->SocketServer-->Twisted(基于select函数或poll函数)

1.    Socket模块

部分函数:

1.connection, address = socket.accept()

服务器套接字通过socket的accept方法等待客户请求一个连接。

accept方法返回一个含有两个元素的元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素address是客户的Internet地址。

2.socket.listen(backlog) 设置一个listen***队列的大小***

backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。

3.socket.connect((host,port) )

使用socket的connect方法连接服务器。

4.socket.setblocking(False) 是否设置为阻塞

5.nthol(x)和ntohs(x)函数要求一个网络字节顺序的数值并把它转换为当前主机字节顺序的相同数值,而htonl(x)和htons(x)则相反:

socket.htons(20000) #转换为一个16位的值

socket.htonl(20000) #转换为一个32位的值

6.setsockopt(level,name,value)和getsockopt(level,name[,buflen])方法来设置和获取套接字的属性。

level参数指定了选项应用于哪一层。level的取值以SOL_开头(SOL_SOCKET,SOL_TCP等等);name表明你涉及的是哪个选项;

value是该选项传入的数值。

对getsockopt,不指定buflen参数意味你要求一个数字值,并返回这个值。如果你提供了buflen,getsockopt返回代表一个缓存的字符串,它的最大长度是buflen的字节数。下面的例子设置了一个socket的用于发送的缓存尺寸为64KB:

s.setsockopt(SOL_SOCKET,SO_SNDBUF,65535)

又如socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR , 1)实现端口重用


[附:C语言实现端口重用:

setsockopt()

设置调用closesocket()后,仍可继续重用该socket。调用closesocket()一般不会立即关闭socket,而经历TIME_WAIT的过程。

BOOL bReuseaddr = TRUE;

setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (const char* )&bReuseaddr, sizeof( BOOL ) );

如果要已经处于连接状态的soket在调用closesocket()后强制关闭,不经历TIME_WAIT过程:

BOOL bDontLinger= FALSE;

setsockopt( s, SOL_SOCKET, SO_DONTLINGER, (const char* )&bDontLinger, sizeof( BOOL ) ); 

]


 socket server and client例子:


2.    SocketServer模块

SocketServer模块简单化了编写网络服务器的工作。它提供了四个基本的服务类:TCPServer(使用TCP协议)、UDPServer(使用数据报)、UnixStreamServer、UnixDatagramServer。UnixStreamServer和UnixDatagramServer用于类Unix平台。

这四个类处理请求都使用同步的方法,也就是说,在下一个请求处理开始之前当前的请求处理必须已完成。

用SocketServer创建一个服务器需要三步:

1、通过子类化BaseRequestHandler类和覆盖它的handle()方法来创建一个请求处理器类,用于处理进来的请求;

2、实例化服务类如TCPServer,并传递给它参数:服务器地址和请求处理器类;

3、调用服务实例对象的handle_request()或serve_forever()方法去处理请求。

下面使用SocketServer用同步的方法写一个最简单的服务器:

from SocketServer import TCPServer, StreamRequestHandler
#第一步。其中StreamRequestHandler类是BaseRequestHandler类的子类,它为流socket定义了
#rfile和wfile方法
class Handler(StreamRequestHandler):
     def handle(self):#处理到来的请求
         addr = self.request.getpeername()
         print 'Got connection from', addr
         self.wfile.write('Thank you for connecting')#send msg to client

#第二步。其中''代表运行服务器的主机
server = TCPServer(('', 12345), Handler)
#第三步。serve_forever()导致进入循环状态
#[server_forever 只是反复调用handle_request而已。]
server.serve_forever()

3.    非阻塞或异步网络编程

序:

服务器端使用阻塞或同步的方法一次只能连接一个客户端,处理完成后才能连接下一个客户端。

例如:Socket方式下Server端程序的执行过程:

一旦服务端socket调用了listen方法,就进入了临听状态,然后通常使用一个无限的循环:1、开始接受客房端的连接,这通过调用accept方法来实现。调用了这个方法后将处于阻塞状态(等待客户端发起连接)直到一个客户端连接,连接后,accept返回形如(client,address)的一个元组,其中client是一个用于与客户端通信的socket,address是客户端的形如xxx.xxx.xxx.xxx:xxx的地址;2、然后服务端处理客户端的请求;3、处理完成之后又调用1。

实现非阻塞主要有三种方法forkingthreading、异步I/O

Forking和threading的方法非常简单,通过使用SocketServer服务类的mix-in类就可以实现forking只适用于类Unix平台;threading需要注意内存共享的问题。

要实现异步I/O,我们可以通过使用框架asyncore/asynchat或Twisted,它们都是基于select函数或poll函数(poll只适于类Unix系统)的。select和poll函数都来自select模块

Twisted是一个事件驱动型的网络引擎。事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。另外两种常见的编程范式是(单线程)同步以及多线程编程。

 

使用 select :

在python中,select函数是一个对底层操作系统的直接访问的接口。它用来监控sockets、files和pipes,等待IO完成(Waiting for I/O completion)。当有可读、可写或是异常事件产生时,select可以很容易的监控到

select.select(rlist, wlist, xlist[, timeout]) 传递三个参数,一个为输入而观察的文件对象列表,一个为输出而观察的文件对象列表和一个观察错误异常的文件列表。第四个是一个可选参数,表示超时秒数(如果超时值没有给出的话,select将处于阻塞状态(也就是等待)直到有文件描述符准备动作。如果超时值给出了,那么select只阻塞给定的时间。如果超时值是0的话,那么将不阻塞。)。其返回3个tuple,每个tuple都是一个准备好的对象列表,它和前边的参数是一样的顺序。

[附:C语言select函数原型

int select(int maxfdp,fd_set*readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

]


 例子:

1.fork server 略

2.threading server

#threading服务器

from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler

class Server(ThreadingMixIn, TCPServer): pass

class Handler(StreamRequestHandler):
    def handle(self):
        addr = self.request.getpeername()
        print 'Got connection from', addr
        self.wfile.write('Thank you for connecting')

server = Server(('', 12345), Handler)
server.serve_forever()
3.select server 

'''
The echo server example from the socket section can be extanded to watche for more than
one connection at a time by using select() .The new version starts out by creating a nonblocking
TCP/IP socket and configuring it to listen on an address
'''
import select
import socket
import Queue
 
#create a socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setblocking(False)
#set option reused  #0119 get reused port
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR  , 1)

host=socket.gethostname()
port=10001
server_address= (host,port) #socket
server.bind(server_address)
 
server.listen(10)
 
#sockets from which we except to read
inputs = [server]#0119 server is the listen socket what we created
 
#sockets from which we expect to write
outputs = []
 
#Outgoing message queues (socket:Queue)
message_queues = {}
 
#A optional parameter for select is TIMEOUT
timeout = 20
 
while inputs:
    print "waiting for next event"
    readable , writable , exceptional = select.select(inputs, outputs, inputs, timeout)
 
    # When timeout reached , select return three empty lists
    if not (readable or writable or exceptional) :
        print "Time out ! "
        break;    
    for s in readable :
        if s is server: #0119 s is the ---listenning socket---
            # A "readable" socket is ready to accept a connection
            connection, client_address = s.accept()
            print "    connection from ", client_address
            connection.setblocking(0)
            inputs.append(connection)
            message_queues[connection] = Queue.Queue()
        else:#0119 s is the ---accepting sockets(the element in inputs list except for 'server') 
            data = s.recv(1024)
            if data :
                print " received " , data , "from ",s.getpeername()
                message_queues[s].put(data) #0119  put an item(received data) in the queue(message_queues[s])
                # Add output channel for response    
                if s not in outputs:
                    outputs.append(s)
            else:
                #Interpret empty result as closed connection(***)
                print "  closing", client_address
                if s in outputs :
                    outputs.remove(s)
                inputs.remove(s)  #0119 inputs.remove(s)  001
                s.close()
                #remove message queue 
                del message_queues[s]
    for s in writable:
        try:
            next_msg = message_queues[s].get_nowait()#0119 Queue.get_nowait() is equivalent to Queue.get(False)
        except Queue.Empty:  #(***)
            print " " , s.getpeername() , 'queue empty'
            outputs.remove(s)
        else:
            print " sending " , next_msg , " to ", s.getpeername()
            s.send(next_msg)
     
    for s in exceptional:
        print " exception condition on ", s.getpeername()
        #stop listening for input on the connection
        inputs.remove(s)   #0119 inputs.remove(s)  002
        if s in outputs:
            outputs.remove(s)
        s.close()
        #Remove message queue
        del message_queues[s]

测试的client代码:
'''
The example client program uses some sockets to demonstrate how the server
with select() manages multiple connections at the same time . The client
starts by connecting each TCP/IP socket to the server
'''
 
import socket
 
messages = ["This is the message" ,
            "It will be sent" ,
            "in parts "]
 
print "Connect to the server"

host=socket.gethostname()
port=10001
server_address= (host,port) #socket
 
#Create a TCP/IP sock
 
socks = []
 
for i in range(4):
    socks.append(socket.socket(socket.AF_INET,socket.SOCK_STREAM))
 
for s in socks:
    while 1:#0119 
        err=s.connect(server_address)
        print err
        if err==-1:
            continue
        else:
            break
 
counter = 0
for message in messages :
    #Sending message from different sockets
    for s in socks:
        counter+=1
        print "  %s sending %s" % (s.getpeername(),message+" version "+str(counter))
        s.send(message+" version "+str(counter))
    #Read responses on both sockets
    for s in socks:
        data = s.recv(1024)
        print " %s received %s" % (s.getpeername(),data)
        if not data:
            print "closing socket ",s.getpeername()
            s.close()

测试运行结果:

server端:

>>> ================================ RESTART ================================
>>> 
waiting for next event
    connection from  ('172.22.144.167', 29326)
waiting for next event
    connection from  ('172.22.144.167', 29327)
waiting for next event
    connection from  ('172.22.144.167', 29328)
waiting for next event
    connection from  ('172.22.144.167', 29329)
waiting for next event
 received  This is the message version 1 from  ('172.22.144.167', 29326)
waiting for next event
 received  This is the message version 2 from  ('172.22.144.167', 29327)
 received  This is the message version 3 from  ('172.22.144.167', 29328)
 received  This is the message version 4 from  ('172.22.144.167', 29329)
 sending  This is the message version 1  to  ('172.22.144.167', 29326)
waiting for next event
  ('172.22.144.167', 29326) queue empty
 sending  This is the message version 2  to  ('172.22.144.167', 29327)
 sending  This is the message version 3  to  ('172.22.144.167', 29328)
 sending  This is the message version 4  to  ('172.22.144.167', 29329)
waiting for next event
  ('172.22.144.167', 29327) queue empty
  ('172.22.144.167', 29328) queue empty
  ('172.22.144.167', 29329) queue empty
waiting for next event
 received  It will be sent version 5 from  ('172.22.144.167', 29326)
 received  It will be sent version 6 from  ('172.22.144.167', 29327)
 received  It will be sent version 7 from  ('172.22.144.167', 29328)
 received  It will be sent version 8 from  ('172.22.144.167', 29329)
waiting for next event
 sending  It will be sent version 5  to  ('172.22.144.167', 29326)
 sending  It will be sent version 6  to  ('172.22.144.167', 29327)
 sending  It will be sent version 7  to  ('172.22.144.167', 29328)
 sending  It will be sent version 8  to  ('172.22.144.167', 29329)
waiting for next event
  ('172.22.144.167', 29326) queue empty
  ('172.22.144.167', 29327) queue empty
  ('172.22.144.167', 29328) queue empty
  ('172.22.144.167', 29329) queue empty
waiting for next event
 received  in parts  version 9 from  ('172.22.144.167', 29326)
 received  in parts  version 10 from  ('172.22.144.167', 29327)
 received  in parts  version 11 from  ('172.22.144.167', 29328)
 received  in parts  version 12 from  ('172.22.144.167', 29329)
waiting for next event
 sending  in parts  version 9  to  ('172.22.144.167', 29326)
 sending  in parts  version 10  to  ('172.22.144.167', 29327)
 sending  in parts  version 11  to  ('172.22.144.167', 29328)
 sending  in parts  version 12  to  ('172.22.144.167', 29329)
waiting for next event
  ('172.22.144.167', 29326) queue empty
  ('172.22.144.167', 29327) queue empty
  ('172.22.144.167', 29328) queue empty
  ('172.22.144.167', 29329) queue empty
waiting for next event
Time out ! 
>>> 
client 端:

>>> ================================ RESTART ================================
>>> 
Connect to the server
None
None
None
None
  ('172.22.144.167', 10001) sending This is the message version 1
  ('172.22.144.167', 10001) sending This is the message version 2
  ('172.22.144.167', 10001) sending This is the message version 3
  ('172.22.144.167', 10001) sending This is the message version 4
 ('172.22.144.167', 10001) received This is the message version 1
 ('172.22.144.167', 10001) received This is the message version 2
 ('172.22.144.167', 10001) received This is the message version 3
 ('172.22.144.167', 10001) received This is the message version 4
  ('172.22.144.167', 10001) sending It will be sent version 5
  ('172.22.144.167', 10001) sending It will be sent version 6
  ('172.22.144.167', 10001) sending It will be sent version 7
  ('172.22.144.167', 10001) sending It will be sent version 8
 ('172.22.144.167', 10001) received It will be sent version 5
 ('172.22.144.167', 10001) received It will be sent version 6
 ('172.22.144.167', 10001) received It will be sent version 7
 ('172.22.144.167', 10001) received It will be sent version 8
  ('172.22.144.167', 10001) sending in parts  version 9
  ('172.22.144.167', 10001) sending in parts  version 10
  ('172.22.144.167', 10001) sending in parts  version 11
  ('172.22.144.167', 10001) sending in parts  version 12
 ('172.22.144.167', 10001) received in parts  version 9
 ('172.22.144.167', 10001) received in parts  version 10
 ('172.22.144.167', 10001) received in parts  version 11
 ('172.22.144.167', 10001) received in parts  version 12
>>> 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很抱歉,我是AI语言模型,无法提供自己的笔记。但是,我可以为您提供一些关于Linux网络编程的信息。Linux网络编程是指在Linux操作系统上进行网络编程的技术,主要包括socket编程、网络协议、网络编程模型等内容。在Linux网络编程中,常用的编程语言有C、C++、Python等。Linux网络编程的应用非常广泛,可以用于开发各种网络应用程序,如Web服务器、邮件服务器、FTP服务器等。同时,Linux网络编程也是网络安全领域的重要技术之一,可以用于网络攻防、数据加密等方面。 ### 回答2: Linux网络编程是一门高级语言编程,包括了网络以及套接字的知识,它的目的是让开发者能够在Linux系统下进行网络应用程序的开发与运行。Linux网络编程中,主要涉及到如下的知识: 1.网络协议:网络协议是数据在计算机网络内传输时所必须遵循的规则和约定。网络协议的共同目标是确保数据的可靠传输。 2.套接字:套接字是一种在网络编程中广泛使用的编程接口,它允许从一个进程向另一个进程通信。通过套接字的编程,可以实现网络上的客户端和服务器端的通信。 3.套接字选项:在套接字编程中,选项提供了一些可选项来控制套接字的行为。例如,可以使用SO_REUSEADDR选项来允许相同的IP地址和端口被多个套接字所使用,或者使用SO_LINGER选项来控制套接字在关闭时的行为。 4.网络编程的主要函数:对于网络编程而言,大多数使用的函数都是socket编程或一些与之相关的函数。如socket、bind、listen、accept、connect、send、recv等。 5.多线程编程和select函数:在网络编程中,常常需要使用多线程编程来同时处理多个套接字,使程序具有高并发性。而select函数可以在一个线程中监听多个套接字的I/O事件,从而优化服务器的性能和响应速度。 6.网络编程的实际应用:网络编程在实际应用中,可以实现许多有趣的功能。例如,可以创建简单的聊天程序、实现网络文件传输、远程控制、实现P2P通信等。 总之,Linux网络编程是一种非常重要的技术,要学习并掌握这门技术,需要掌握网络协议、套接字、多线程编程等基础知识。掌握这些知识后,开发者可以根据实际需求,灵活地使用网络编程技术来实现各种基于网络的应用程序。 ### 回答3: Linux网络编程在现代软件开发中扮演着非常重要的角色,这是因为它是一种跨平台的操作系统,并且为开发人员提供了良好的网络编程接口。以下是一些重要的技术和笔记: 1. 套接字(socket)编程—— 在Linux环境中,套接字是网络编程的关键要素。它被用于实现客户端/服务器应用程序中的通信,例如Web服务器和聊天室应用程序。在编写套接字程序时,必须使用包括bind,listen和accept等操作来处理连接请求。 2. 网络协议—— Linux支持各种网络协议,例如TCP/IP,UDP,ICMP,ARP和RIP等。其中TCP/IP是最常用的网络协议,因为它可靠且易于使用,在开发网络应用程序时需要具备其相关知识,例如TCP连接管理和协议数据包的格式化。 3. 多线程编程—— 在Linux环境中,多线程编程是一种非常重要的技术,可以同时处理多个网络请求,以提高应用程序的性能。通常使用POSIX线程库(pthread)来实现多线程编程,并使用同步和互斥机制来管理线程访问共享变量的冲突。 4. 网络安全—— 网络安全是Linux网络编程的一个重要方面,因为网络应用程序通常需要保护敏感数据和隐私信息。开发人员必须学习诸如SSL和TLS等加密协议,以确保数据传输的安全性。 总结来说,在Linux环境下进行网络编程需要熟悉套接字编程、网络协议、多线程编程和网络安全等技术。这些技术的结合可以实现高效的网络应用程序,并提高用户体验。在掌握这些技术后,开发人员可以将网络编程应用于Web服务器、聊天室应用程序、数据存储器等各种应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值