python socket 笔记

创建sock = socket.socket()

    sock.bind(sock_addr) #sock_addr = (host,port)

    sock.connect(sock_addr)   #客服端

    sock.listen(num) # num>=1  #监听

    connectsock,addr = sock.accept() #接收

    sock.settimeout(time) #超时

    sock.recv(size) #接收数据

    sock.send(data)#发送数据

    sock.sendall(data)#发送数据

    sock.dup()#返回一个新的套接字

    sock.setblocking(0)#设置sock为非阻塞模式

 

 

  • 表2. Socket 模块的类方法

类方法

说明

Socket

低层网络接口(每个 BSD API)

socket.socket(family, type)

创建并返回一个新的 socket 对象

socket.getfqdn(name)

将使用点号分隔的 IP 地址字符串转换成一个完整的域名

socket.gethostbyname(hostname)

将主机名解析为一个使用点号分隔的 IP 地址字符串

socket.fromfd(fd, family, type)

从现有的文件描述符创建一个 socket 对象

  • 表3. Socket 模块的实例方法

实例方法

说明

sock.bind( (adrs, port) )

将 socket 绑定到一个地址和端口上

sock.accept()

返回一个客户机 socket(带有客户机端的地址信息)

sock.listen(backlog)

将 socket 设置成监听模式,能够监听 backlog 外来的连接请求

sock.connect( (adrs, port) )

将 socket 连接到定义的主机和端口上

sock.recv( buflen[, flags] )

从 socket 中接收数据,最多 buflen 个字符

sock.recvfrom( buflen[, flags] )

从 socket 中接收数据,最多 buflen 个字符,同时返回数据来源的远程主机和端口号

sock.send( data[, flags] )

通过 socket 发送数据

sock.sendto( data[, flags], addr )

通过 socket 发送数据

sock.close()

关闭 socket

sock.getsockopt( lvl, optname )

获得指定 socket 选项的值

sock.setsockopt( lvl, optname, val )

设置指定 socket 选项的值

struct的pack和unpack方法

[转]http://wwty.iteye.com/blog/401414 

我很诚实的表明转发地址哈哈 为了方便自己以后查找

---------------------------------------------

这两天做TCP协议,数据的传输都是二进制的,需要解释,于是用到了struct
看到这样一句代码:
  

Python代码  收藏代码

  1. length = struct.unpack('>I'self.buffer[:4])[0]  

 当时没有明白format=">I"是什么意思,从google找了一下,有人说这个东西,可都是比较笼统,没能让我明白,于是硬着头皮看API:
By default, C numbers are represented in the machine’s native format and byte order, and properly aligned by skipping pad bytes if necessary (according to the rules used by the C compiler).
通常,C语言下数字都是机器语言的格式并且按照字节排序,同时在需要的情况下会利用跳过填补的字节来进行适当的调整

 

Alternatively, the first character of the format string can be used to indicate the byte order, size and alignment of the packed data。
非此即彼:字符串的第一个字符要么被用于表示字符串的字节的排序,或者是字符串的size,还有就是数据是否对准。


 

Native byte order is big-endian or little-endian, depending on the host system. For example, Motorola and Sun processors are big-endian; Intel and DEC processors are little-endian.
计算机的字节序要么是高位顺序,要么是低位的,这依赖于主机本身。比如,摩托罗拉和sun的处理器是高位的,但是intel和DEC的是低位的。

 

这样子就明白了上面的format=">I"的意思,也就是说按照高位顺序来格式化取得一个int或long值。下面问题就又来了,你怎么知道读取的就是一个int或long值呢?

通过看struct的文档,可以看到struct通过两张表制定了一定的format规则,我按照自己的观察,给他归纳为两类,一个是和C当中类型的对照,另一个就是选择按照高位还是低位来解释字节。上面已经说了高低字节顺序,那么观察和C对照的表格,发现I 代表的就是integer or long ,详细的可以去看python的API。

 

下面是一些使用的例子,具体的使用,可以参考这些例子:
1. 设置fomat格式,如下: 
# 取前5个字符,跳过4个字符华,再取3个字符 
format = '5s 4x 3s'

2. 使用struck.unpack获取子字符串 
import struct 
print struct.unpack(format, 'Test astring') 
#('Test', 'ing') 
来个简单的例子吧,有一个字符串'He is not very happy',处理一下,把中间的not去掉,然后再输出。 
import struct 
theString = 'He is not very happy' 
format = '2s 1x 2s 5x 4s 1x 5s' 
print ' '.join(struct.unpack(format, theString)) 
输出结果: 
He is very happy

 

 

随后是关于网络字节的东东,从网上看来的,感觉有用:

Python的socket库采用string类型来发送和接收数据,这样当我们用
i = socket.recv(4)
来接收一个4字节的整数时,该整数实际上是以二进制的形式保存在字符串 i 的前4个字节中;大多数的时候我们需要的是一个真正的integer/long型,而不是一个用string型表示的整型。这时我们可以使用struct库:Interpret

strings as packed binary data. 对上面的情况,我们可以写
t = unpack("I", i)
第一个参数是格式化字符串,I指明字符串 i 包含的头一个数据项是一个以C语言的unsigned integer表示的整数,这里 i 只包含了一个数据项,实际上这个被解释的字符串也可以包含多个数据项,只要在格式化字符串里为每项数据指明一个格式即可;自然地,unpack返回的就是一个tuple类型了。

获取notification发送用户以及用户如何对应用户组

    今天因为 Ho Sean Shan又收不到邮件了所以我去找原因,还是比较懒散,不情愿去深读代码,其实要是深读了是很简单的,其实就是if else判断顺着理下去就好了,原因是这个notification的exclude_current_user 选项被打开了,所以排除了当前操作的用户,而Sean就是去Request这个action的人,所以当然看不见喽。

那通过今天一方面了解了notification是怎样获取到用户的
private function _notification_get_target( $notification_details, $key )
 {
  $this->load->model('acl/acl_aro');
  
  $key;//target, target_cc, target_bcc
  $type_key = $key . '_type';
  
  $targets = array();
  if($notification_details[$type_key] == 'role')
  {
   $role_names = explode(',', $notification_details[$key]);
   foreach($role_names as $role_name)
   {
    $role_name = trim($role_name);
    $all_users = $this->acl_aro->get_role_users_by_role_name($role_name);
    
    foreach($all_users as $user_details)
    {
     if($notification_details['exclude_current_user'] == 'N' || $user_details['user_id'] != $this->_user_id)
     {
      $targets = $this->_add_valid_email_into_target( $user_details['user_email'], $targets );
     }
    }
   }
  }
  elseif( $notification_details[$type_key] == 'email' )
  {
   $emails = explode(',', $notification_details[$key]);
   
   foreach($emails as $email)
   {
    $email = trim($email);
    $targets = $this->_add_valid_email_into_target( $email, $targets );
   }
  }
  elseif( $notification_details[$type_key] == 'user' )
  {
   $user_ids = explode(',', $notification_details[$key]);
   foreach($user_ids as $user_id)
   {
    $user_id = trim($user_id);
    $user_details = $this->acl_aro->get_user_info('', $user_id);
    $targets = $this->_add_valid_email_into_target( $user_details['user_email'], $targets );
   }
  }
  
  //add the current user to be in CC list.
  if($key == 'target_cc' && $notification_details['target_cc_current_user'] == 'Y')
  {
   $user_details = $this->acl_aro->get_user_info('', $this->_user_id);
   $targets = $this->_add_valid_email_into_target( $user_details['user_email'], $targets );
  }
  
  return $targets;
 }
另一方面是用户如何对应用户组
SELECT c.*
FROM  evo_central_config.acl_user_role a, evo_central_config.acl_aro_role b, evo_central_config.customer_user c
WHERE a.role_id = b.role_id
AND   b.role_name = 'CSM_VMS_CSA'
AND   a.user_id = c.user_id
AND   c.is_active = 'Y'

python网络编程学习笔记(1)

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



学习用书:《python 网络编程基础》作者John Goerzen

第一部分底层网络学习

        Python提供了访问底层操作系统Socket接口的全部方法,需要的时候这些接口可以提供灵活而强有力的功能。

(1)基本客户端操作

        在《python 网络编程基础》一书中,作者列出了一个简单的Python客户端程序,具体如下:

复制代码
import socket,sys
port =70
host=sys.argv[1]

filename=sys.argv[2]

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))

s.sendall(filename+"\r\n")

while 1:
    buf=s.recv(2048)
    if not len(buf):
        break
    sys.stdout.write(buf)
复制代码

 

        该程序实现的是Gopher协议,实现从主机上请求相关文档的功能。(Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本很少被使用。)

       于是,我按照书上的语句进行了一下测试,在dos下运行python gopherclient.py quux.org。但是系统提示为

Traceback (most recent call last):

File "gopherclient.py", line 5, i

filename=sys.argv[2]

IndexError: list index out of range

看了一下,sys.argv只有两个元素['gopherclient.py', 'quux.org/']所以filename=sys.argv[2]就超出下界了。可是为什么会出现这个原因呢?是书里面写错了吗,因为我也是初学socket,不是很了解,所以我也是没有找到原因,如果哪位大牛知道是什么原因,希望能给讲解一下。

(2)基本服务器操作

        《python 网络编程基础》一书中同样给出了一个简单的服务器程序,具体如下:

复制代码
import socket
host=''
port=51423
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host,port))
s.listen(1)

print "Server is running on port %d;press Ctrl-C to terminate." %port
while 1:
    clientsock,clientaddr=s.accept()
    clientfile=clientsock.makefile('rw',0)
    clientfile.write("welcome,"+str(clientaddr)+'\n')
    clientfile.write("Please enter a string:")
    line=clientfile.readline().strip()
    clientfile.write("You entered %d characters.\n" %len(line))
    clientfile.close()
    clientsock.close()
复制代码

 

        该程序运行后,提示“Server is running on port 51423:press Ctrl-C to terminate”。此时,通过另一台机器telnet本机器的51423端口,如telnet 127.0.0.1:51423,此时会提示welcome 127.0.0.1 ****,please enter a string:。 然后输入几个字符后,会返回你输入字符的个数。

这里就该程序进行一下分析:

1、首先导入socket模块,给host和port赋值。

2、调用socket.socket()来建立一个socket赋值给s。socket.socket(domain, type, protocol).domain参数的值有AF_UNIX,AF_LOCAL,AF_INET,PF_UNIX,PF_LOCAL,PF_INET。这几个值中AF_UNIX=AF_LOCAL, PF_UNIX=PF_LOCAL, AF_LOCAL=PF_LOCAL, AF_INET=PF_INET。一般来说,AF 表示ADDRESS FAMILY 地址族,PF 表示PROTOCOL FAMILY 协议族,但这两个宏定义是一样的,所以使用哪个都没有关系。参数type指定socket的类型:SOCK_STREAM提供有序、可靠、双向及基于连接的字节流。SOCK_DGRAM支持数据报。SOCK_SEQPACKET提供有序、可靠、双向及基于连接的数据报通信。SOCK_RAW提供对原始网络协议的访问。SOCK_RDM提供可靠的数据报层,但是不保证有序性。protocol一般取0(为什么取0我也没搞清楚,放在以后明白了再写上吧)

3、s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)。setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。 这个函数中,第一个参数为协议层参数,指明了希望访问一个选项所在的协议栈。通常我们需要使用下面中的一个:

SOL_SOCKET来访问套接口层选项

SOL_TCP来访问TCP层选项

第二个参数是与第一个参数相对应的。第一个参数决定了协议层level,第二个参数决定了该协议层下选项组合。SOL_SOCKET的选项组合如下:

协议层 选项名字

SOL_SOCKET SO_REUSEADDR

SOL_SOCKET SO_KKEPALIVE

SOL_SOCKET SO_LINGER

SOL_SOCKET SO_BROADCAST

SOL_SOCKET SO_OOBINLINE

SOL_SOCKET SO_SNDBUF

SOL_SOCKET SO_RCVBUF

SOL_SOCKET SO_TYPE

SOL_SOCKET SO_ERROR

具体的一些组合用法可见:http://wenku.baidu.com/view/23013b7101f69e3143329402.html

第三个参数设为1,这里我也没很明白其中的意思,我试着把1换成50,结果是一样的。换成0也是可以的,没发现什么区别。希望大牛们给指点一下。

4、s.bind((host,port))绑定主机端口。

5、s.listen(1):listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。这里的参数涉及到一些网络的细节。在进程正理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。这里设定为1表示每次最多只有一个等候处理的连接。

6、while循环从accept()函数开始。程序会在连接了一个客户端后关闭socket。当某个客户端连接的时,accept返回两个信息,一个新的连接客户端socket和客户端的ip地址、端口号。如在上面的例子中添加print语句输出clientsock和clientaddr,你会发现clientsock为socket.socketobject,clientaddr=('客户端Ip',端口)。后面的循环中使用了文件类对象,服务器接着显示出一些介绍性信息,从客户端读一个字符串,显示一个应答,最后关闭客户端socket。

linux下保持python窗口持续运行–screen

今天在学习python 的 tornado 运行了一个小博客呵呵 还挺好玩的,但是遇到一个问题就是我用putty一断开连接就无法访问这个接口了,那如果要运行一个博客肯定是要持续的,而又不能用一台电脑永远连接着这个窗口,而且持续链接窗口因为各种原因要是连接断了这不是坑爹么,所以到群里问了一下,群友给建议:

 
开个screen
screen -S xxx 

 

所以我就百度了一下 找到一篇比较详细的记录下来供以后使用。

====================================================================

 

“首先用screen [-S]命令建立一个session,然后就可以在这个session中建立多个window了。使用screen [-S]可以建立多个session,而每个session又可以建立多个window。在不同的window之间可以用Ctrl-A n/p等命令来切换。而想要在多个session之间切换,则需要你Ctrl-A d回到登录session(就像一棵大树的根),然后再通过screen -ls查看有哪些session,然后使用screen -r来决定恢复到哪个session。对于已经Attached Session则不能直接screen -r,需要先screen -d,然后才能screen -r”

 

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

【转载1】

系统管理员经常需要远程登录服务器
然后在服务器上跑一些程序
有个时候
得跑很长时间(超过12小时)
这是如果程序没结束就退出远程管理终端
远程跑的程序很有可能就此当掉
以前常用的解决方式是用命令nohup
但是nohup也有很多的问题
当有了screen
这一切便都迎刃而解了
敲入命令screen
会创建一个跑着shell的单一窗口
在这里面
你可以跑你所需要的程序
然后Ctrl+a d退出刚创建的窗口(回到进入screen前的环境)
然后再敲入命令screen创建新的终端窗口
就这样
你可以建立多个有shell的窗口(这些窗口里都可以跑你自己的应用)
这样就是你退出远程管理窗口(进入screen的环境)
你的screen窗间的窗口都不会关闭
里面跑得应用自然也不会当掉
用screen -ls可以看所有的screen sessions
用screen -r sessionid可以进sessionid指定的特定的screen session
最后screen session不再使用的时候
screen -r sessionid进去
exit退出即可


Unix/Linux 工具: Screen 命令使用
screen使用
使用screen非常简易.只需在SHELL键入screen,便可打开一个screen session。
而在每个screen session 下,所有命令都以 ctrl+a(C-a) 开始。
现在让我来简单介绍基本的命令
C-a c -> Create,开启新的 window
C-a n -> Next,切换到下个 window
C-a p -> Previous,前一个 window
more.. 
C-a C-a -> Other,在两个 window 间切换
C-a w -> Windows,列出已开启的 windows 有那些
C-a 0 -> 切换到第 0 个 window
C-a 1..9 -> 切换到第 1..9 个window
C-a a -> 发出 C-a,在 emacs, ve, bash, tcsh 下可移到行首
C-a t -> Time,显示当前时间,和系统的 load
C-a K(大写) -> kill window,强行关闭当前的 window
C-a [ -> 进入 copy mode,在 copy mode 下可以回滚、搜索、
复制就像用使用 vi 一样
C-b Backward,PageUp
C-f Forward,PageDown
H(大写) High,将光标移至左上角
L Low,将光标移至左下角
0 移到行首
$ 行末
w forward one word,以字为单位往前移
b backward one word,以字为单位往后移
Space 第一次按为标记区起点,第二次按为终点
Esc 结束 copy mode
C-a ] -> Paste,把刚刚在 copy mode 选定的内容贴上
C-a ? -> Help,显示简单说明
C-a d -> detach,将目前的 screen session (可能含有多个 windows)
丢到后台执行 当按了 C-a d 把 screen session detach 掉后,会回到还没进 screen 时的状态,此时在 screen session 里每个 window 内运行的 process (无论是前台/后台)都在继续执行,即使 logout 也不影响。
下次 login 进来时:
screen -ls -> 显示所有的 screen sessions
screen -r [keyword] -> 选择一个screen session 恢复对话
若 screen -ls 里有 Attached sessions:
screen -d [keyword] -> 强制 detach,以便「接手」过来 


实例:
说明看了那么多,让我们用一个实际例子来结束我们今天的学习。
在我们开启一个screen后,然后使用joe编辑一个文件,之后因为临时需要离开这时就可以运行Ctrl+a d,显示如下:
[becks@ec-base becks]$ screen
[detached]
这个时候当我们运行ps -e 可以看到pts/2这个我刚刚运行的screen正在运行joe
6264 pts/2 00:00:00 bash
6354 pts/2 00:00:00 joe
而当我们回来后想恢复这个session,只需要键入screen -r,而当你有多个session时候,系统将提示你选择一个,如下:
[becks@ec-base becks]$ screen -r
There are several suitable screens on:
6263.pts-1.ec-base (Detached)
6382.pts-1.ec-base (Detached)
Type "screen [-d] -r [pid.]tty.host" to resume one of them.
输入该session的pid进行恢复
[becks@becks becks]$ screen -r 6263
想退出screen的session,和退出shell一样,只需要键入exit命令,成功退出后将有以下提示
[screen is terminating]

 

【转载2】

linux screen 命令详解

功能说明: 

使用telnet或SSH远程登录linux时,如果连接非正常中断,重新连接时,系统将开一个新的session,无法恢复原来的session.screen命令可以解决这个问题。Screen工具是一个终端多路转接器,在本质上,这意味着你能够使用一个单一的终端窗口运行多终端的应用。

语  法:

screen [-AmRvx -ls -wipe][-d <作业名称>][-h <行数>][-r <作业名称>][-s ][-S <作业名称>]

补充说明:

screen为多重视窗管理程序。此处所谓的视窗,是指一个全屏幕的文字模式画面。通常只有在使用telnet登入主机或是使用老式的终端机时,才有可能用到screen程序。

参  数:

-A  将所有的视窗都调整为目前终端机的大小。
-d <作业名称>  将指定的screen作业离线。
-h <行数>  指定视窗的缓冲区行数。
-m  即使目前已在作业中的screen作业,仍强制建立新的screen作业。
-r <作业名称>  恢复离线的screen作业。
-R  先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-s  指定建立新视窗时,所要执行的shell。
-S <作业名称>  指定screen作业的名称。
-v  显示版本信息。
-x  恢复之前离线的screen作业。
-ls或–list  显示目前所有的screen作业。
-wipe  检查目前所有的screen作业,并删除已经无法使用的screen作业。

常用screen参数:

screen -S yourname -> 新建一个叫yourname的session
screen -ls -> 列出当前所有的session
screen -r yourname -> 回到yourname这个session
screen -d yourname -> 远程detach某个session
screen -d -r yourname -> 结束当前session并回到yourname这个session

在每个screen session 下,所有命令都以 ctrl+a(C-a) 开始。

C-a ? -> Help,显示简单说明
C-a c -> Create,开启新的 window
C-a n -> Next,切换到下个 window 
C-a p -> Previous,前一个 window 
C-a 0..9 -> 切换到第 0..9 个window
Ctrl+a [Space] -> 由視窗0循序換到視窗9
C-a C-a -> 在两个最近使用的 window 间切换 
C-a x -> 锁住当前的 window,需用用户密码解锁
C-a d -> detach,暂时离开当前session,将目前的 screen session (可能含有多个 windows) 丢到后台执行,并会回到还没进 screen 时的状态,此时在 screen session 里    每个 window 内运行的 process (无论是前台/后台)都在继续执行,即使 logout 也不影响。 
C-a z -> 把当前session放到后台执行,用 shell 的 fg 命令則可回去。
C-a w -> Windows,列出已开启的 windows 有那些 
C-a t -> Time,显示当前时间,和系统的 load 
C-a K -> kill window,强行关闭当前的 window

tornado RequestHandler

我还在纳闷 Class里定义的get方法是怎么调用的呢

加入了一个tornado的群,问了一下人才知道get是http 的get请求···

尼玛坑啊~真真的很方便啊这样就获取了

具体的参考 tornador 的 RequestHandler

tornado安装记

今天本来是在mac上安装的,后来辗转到了win7的电脑上,又辗转到了服务器的centos上。

主要还是我没有恒心,觉得在前2者上安装参资料太少,上国外论坛逛了一圈又发现还是比较麻烦。

何况tornado本身的东西也是基于lunux的xxx在win上只能用select替代很多东西也用不起来

于是,嘿嘿,图懒省事就在centos上搭建了。

 

刚学习python时间还是很短的,

以至于安装setup.py文件的时候 我还会写成“python setup.py”

上网找了一下才知道应该是“python setup.py install”

唉其实在centos上安装我觉得也够麻烦,先后安装了curl,pypa-setuptools,backports.ssh_match_hostnaem

查了一下资料3.0后的tornado在python3以下好象是依赖于backports.ssh_match_hostnaem这个包

 

坑啊,全部弄完之后执行了示例代码:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

 

才正常运行了~不容易啊~~~慢慢吧。