1 Python socket 基础 Server - Foundations of Python Socket
 2 
 3 通过 python socket 模块建立一个提供 TCP 链接服务的 server 可分为 4 个步骤,
 4     1, 建立 socket 对象
 5         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 6     2, 设置 socket 选项(可选)
 7         s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 8         在一个服务器进程终止后,操作系统通常会保留几分端口,这样在超时之前这个
 9         端口先属于被占用状态,不可被其他程序使用. 若设置 SO_REUSEADDR 为 true,
10         则操作系统会在 socket 关闭后立刻释放它的端口.
11     3, 绑定到一个端口, 或一个网卡
12         s.bind((host, port))
13             host 参数可以为空 '', 意思是绑定到所有的地址.
14             一个 use case 是, 一台 PC 有多个网卡, 一张网卡链接到公共的 Internet 上,
15             另一张网卡链接在内部网路上。如果希望服务只对内部网路可见, 可以同过 bind()
16             方法将服务绑定到内部网路的 IP 地址上. 这样对于通过公共的 Internet 访问的
17             用来所来服务是不可见的。
18     4, 监听链接请求
19         s.listen(5)
20             该方法通知操作系统准备接受链接请求. 方法接收一个 int 类型参数, 含义是指明
21             服务器处理链接的时候,允许有多少个等待的链接在队列中 queue.
22 
23 响应连接请求,
24     while 1:
25         clientsocket, clientaddr = s.accept()
26         print("%s is connecting" % clientsocket.getpeername())
27             accept()方法会 阻塞 程序, 当一个客户端连接后才返回
28 
29 异常处理,
30     任何没有被捕获到异常都会到时程序终止, 然而这种情况对于服务端而言是非常不好的.
31     因为异常将到时整个服务器关闭,并停止响应请求,从而不得不重启服务端以回复服务.            
32     一个健壮的服务端程序,应该捕获任何错误和异常并对其做适当的处理,从而保证服务不会被终止.
33     import traceback
34     while 1:
35         try:
36             clientsocket, clientaddr = s.accept()
37         except KeyboardInterrupt as e:             # Ctrl-C 可以终止程序
38             raise e
39         except:
40             traceback.print_exc()                  # 捕获所以其他异常,并打印
41             continue                               # 下一循环,而非终止程序
42         try:
43             print("%s is connecting" % clientsocket.getpeername())
44         except (KeyboardInterrupt,SystemExit):     # Ctrl-C 和 sys.exit()
45             raise
46         except:
47             traceback.print_exc()                  # 打印其他异常
48     
49         try:
50             clientsocket.close()                   # 进入第二个 try 代码块儿后,
51                                                    # 无论是否有异产生 close() 方法都应该被调用.
52         except KeyboardInterrupt:                  # 第二,三个 try 代码块,可以合并成
53                                                    # try ...  finally 的结构保证 close()的调用.
54             raise
55         except:
56             traceback.print_exc()