多线程原理:TCP服务器会创建一个线程池,每当有客户端请求连接的时候,它便会从线程池中分配一个线程同客户端建立连接,当客户端中断连接后,线程便销毁。

  SocketServer 是标准库中一个高级别的模块。用于简化网络客户与服务器的实现。

  socketserver模块中分两大类:server类(解决连接问题)和request类(解决通信问题)

  我们将服务器做为中转站来处理信息,一方面与客户端互动,另一方面进行消息转发。

  大体思路确定下来后,需要确定一些通信规则:

  1. 客户端与服务器建立连接后,需要输入用户名登入,若用户名已存在,将reuse反馈给用户,用户输出错误信息,退出

  2. 用户输入正确的用户名后,即可进行通信了。如果未选择通信对象,则服务器会反馈信息,提示用户选择通信对象

  3. 选择通信对象的方法为,输入to:username,如果所选择的对象不存在,反馈错误信息,重新输入

  4.当正确选择通信对象后,双方建立连接,通过服务器中转信息进行通信

  5.在通信中,若发送‘quit',则结束发送消息的线程,并指示服务器该用户准备登出,服务器删除该用户后,反馈消息给用户,用户结束接收消息的线程并退出

  6.如果A正在与C通信,此时B向A发送信息,则A的通信窗口变为与B的通信窗口,即接收到B消息后,A发出的消息不再是给C,而是默认给B

  实现代码:

  #!/usr/bin/python

  'test TCP server'

  from socket import *

  from time import ctime

  import threading #多线程模块

  import re #正则表达式模块

  HOST = ''

  PORT = 21567

  BUFSIZ = 1024

  ADDR = (HOST, PORT)

  def Deal(sock, user):

  while True:

  data = sock.recv(BUFSIZ) #接收用户的数据

  if data == 'quit': #用户退出

  del clients[user]

  sock.send(data)

  sock.close()

  print '%s logout' %user

  break

  elif re.match('to:.+', data) is not None: #选择通信对象

  data = data[3:]

  if clients.has_key(data):

  chatwith[sock] = clients[data]

  chatwith[clients[data]] = sock

  else:

  sock.send('the user %s is not exist' %data)

  else:

  if chatwith.has_key(sock): #进行通信

  chatwith[sock].send("[%s] %s: %s" %(ctime(), user, data))

  else:

  sock.send('Please input the user who you want to chat with')

  tcpSerSock = socket(AF_INET, SOCK_STREAM)

  tcpSerSock.bind(ADDR)

  tcpSerSock.listen(5)

  clients = {} #提供 用户名->socket 映射

  chatwith = {} #提供通信双方映射

  while True:

  print 'waiting for connection...'

  tcpCliSock, addr = tcpSerSock.accept()

  print '...connected from:',addr

  username = tcpCliSock.recv(BUFSIZ) #接收用户名

  print 'The username is:',username

  if clients.has_key(username): #查找用户名

  tcpCliSock.send("Reuse") #用户名已存在

  tcpCliSock.close()

  else:无锡妇科医院排行 http://www.0510bhyy.com/

  tcpCliSock.send("Welcome!") #登入成功

  clients[username] = tcpCliSock

  chat = threading.Thread(target = Deal, args = (tcpCliSock,username)) #创建新线程进行处理

  chat.start() #启动线程

  tcpSerSock.close()

  #!/usr/bin/python

  'test tcp client'

  from socket import *

  import threading

  HOST = 'localhost'

  PORT = 21567

  BUFSIZ = 1024

  ADDR = (HOST, PORT)

  threads = []

  def Send(sock, test): #发送消息

  while True:

  data = raw_input('>')

  tcpCliSock.send(data)

  if data == 'quit':

  break

  def Recv(sock, test): #接收消息

  while True:

  data = tcpCliSock.recv(BUFSIZ)

  if data == 'quit':

  sock.close() #退出时关闭socket

  break

  print data

  tcpCliSock = socket(AF_INET, SOCK_STREAM)

  tcpCliSock.connect(ADDR)

  print 'Please input your username:',

  username = raw_input()

  tcpCliSock.send(username)

  data = tcpCliSock.recv(BUFSIZ)

  if data == 'Reuse':

  print 'The username has been used!'

  else:

  print 'Welcome!'

  chat = threading.Thread(target = Send, args = (tcpCliSock,None)) #创建发送信息线程

  threads.append(chat)

  chat = threading.Thread(target = Recv, args = (tcpCliSock,None)) #创建接收信息线程

  threads.append(chat)

  for i in range(len(threads)): #启动线程

  threads[i].start()

  threads[0].join() #在我们的设计中,send线程必然先于recv线程结束,所以此处只需要调用send的join,等待recv线程的结束。