准备连接
1. 客户端建立一个TCP连接分为2步,包括建立socket对象以及调用connect建立一个和服务器的连接,而对于服务器则需要建立socket对象,设置socket选项(可选的),绑定到一个端口(同样,也可以是一个指定的网卡),侦听连接
建立socket对象
cur_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
设置和得到socket选项
cur_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
cur_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
1. socket.SO_REUSEADDR标志位为True时,表示当socket关闭后,本地端用于该socket的端口号立刻就可以被重用,默认情况下端口会经过一段时间才会被释放
2. socket.SO_KEEPALIVE标识位为True时,可以使TCP通信的信息包保持连续性,这些信息包可以在没有信息传输时,使通信的双方确定连接是保持的
绑定socket
cur_socket.bind((bind_host, bind_port))
1. host为空字符串时表示可以绑定到所有的接口和地址
侦听连接
client_sock, client_addr = cur_socket.accept()
接受连接
1. 大多数服务器都设置成运行不确定长时间和同时服务于多个连接,常使服务器连续运行的办法是设计一个无限循环
2. 无限循环会耗净CPU资源,然后这里循环不同,当调用accept时,它只在有一个客户端连接后才返回,此时其实是被阻塞的
处理错误
1. 服务端一般出现错误并不会关闭服务器,停止响应请求,常常会打印错误并且略过错误
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
#
# Authors: limanman
# OsChina: http://my.oschina.net/pydevops/
# Purpose:
#
"""
import sys
import socket
import threading
# 接受连接的线程
def accept_thread(cur_socket):
"""Generate accept thread.
Args:
cur_socket: socket with bind (host, port)
Returns:
bool
"""
server_info = cur_socket.getsockname()
client_sock, client_addr = cur_socket.accept()
print 'notice: client %s -> server %s' % (repr(client_addr),
repr(server_info))
while True:
try:
cur_buffer = client_sock.recv(2048)
except (KeyboardInterrupt, SystemExit):
cur_socket.close()
return False
if not cur_buffer.strip():
cur_socket.close()
return False
client_sock.sendall('Recived: %s' % (cur_buffer.upper()))
# 主函数
def main():
"""Main function.
"""
# 接受连接的线程列表
accept_thread_list = []
# 主机设置为空字符串,程序可以接受来自任意地方的连接
bind_host = ''
bind_port = 8888
# 建立SOCKET
try:
cur_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, e:
sys.exit('errors: creating socket with error %s' % (e))
# SOCKET设置为可复用
cur_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
bind_port = int(bind_port)
except ValueError, e:
try:
bind_port = socket.getservbyname(bind_port, 'TCP')
except socket.error, e:
sys.exit('errors: resolver port with error %s' % (e))
try:
cur_socket.bind((bind_host, bind_port))
except socket.error, e:
sys.exit('errors: bind with error %s.' % (e))
# 开始等待来自客户端连接,默认最多只有1个等待处理的连接
cur_socket.listen(1)
# 新建10个等待连接
for _ in xrange(10):
accept_thread_list.append(threading.Thread(target=accept_thread,
args=(cur_socket,)))
# 并行运行接受连接
for cur_thread in accept_thread_list:
cur_thread.start()
if __name__ == '__main__':
main()
使用UDP
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
#
# Authors: limanman
# OsChina: http://my.oschina.net/pydevops/
# Purpose:
#
"""
import sys
import socket
import threading
# 主函数
def main():
"""Main function.
"""
bind_host = ''
bind_port = 8888
try:
cur_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error, e:
sys.exit('errors: creating socket with error %s' % (e))
cur_socket.bind((bind_host, bind_port))
server_addr = cur_socket.getsockname()
# 没有连接概念,客户端每个连接用不同的自动变化端口
while True:
client_msg, client_addr = cur_socket.recvfrom(2048)
print 'notice: client %s -> server %s' % (repr(client_addr),
repr(server_addr))
cur_socket.sendto('Recived: %s' % (client_msg.upper()), client_addr)
if __name__ == '__main__':
main()