聊天web项目

来源:互联网 发布:python 图片加水印 编辑:程序博客网 时间:2024/06/12 00:08
# coding: utf-8    from socket import *  import json, time, threadingimport structfrom urllib import unquoteconfig = {      'HOST': 'localhost',      'PORT': 11011,      'LISTEN_CLIENT': 50,      'KEY': '391f10fadc339e9ec5fa15af60030ac1',      'SIZE': 2048,      'TIME_OUT': 1000,      'HEART_TIME': 5,      'MAGIC_STRING': '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',      'HANDSHAKE_STRING': "HTTP/1.1 101 Switching Protocols\r\n"               "Upgrade:websocket\r\n"               "Connection: Upgrade\r\n"               "Sec-WebSocket-Accept: {1}\r\n"               "WebSocket-Location: ws://{2}/chat\r\n"              "WebSocket-Protocol:chat\r\n\r\n"  }      class Server():      """     服务端基类     """      def __init__(self):          self.sock = socket(AF_INET, SOCK_STREAM)          self.sock.bind((config['HOST'], config['PORT']))  # 监听端口          self.sock.listen(config['LISTEN_CLIENT'])  # 监听客户端数量            # 所有监听的客户端          self.clients = {}          self.thrs = {}          self.users = {}          self.stops = []        print u"\n正在监听端口..."      # 监听客户端连接      def listen_client(self):          while 1:              # 循环监听              tcpClientSock,addr = self.sock.accept()              address = addr[0] + ':' + str(addr[1])  # ip:port                                  # 握手              topInfo = tcpClientSock.recv(1024)                         headers = {}                       #print u'\n服务端发送的信息:', address                        if not topInfo:                  tcpClientSock.close()                  continue                header, data = topInfo.split('\r\n\r\n', 1)                try:                  getInfo = header.split('\r\n')[0].split(' ')[1].split('/')[1:]                  if getInfo[0] == 'name':                      self.users[address] = str(getInfo[1])                  else:                      self.users[address] = '匿名用户'              except:                  self.users[address] = '匿名用户'                  for line in header.split('\r\n')[1:]:                  key, val = line.split(': ', 1)                  headers[key] = val                if 'Sec-WebSocket-Key' not in headers:                  tcpClientSock.close()                  continue                import hashlib, base64              sec_key = headers['Sec-WebSocket-Key']              res_key = base64.b64encode(hashlib.sha1(sec_key + config['MAGIC_STRING']).digest())                str_handshake = config['HANDSHAKE_STRING'].replace('{1}', res_key).replace('{2}', config['HOST'] + ':' + str(config['PORT']))              tcpClientSock.send(str_handshake)            try:                  username = unquote(self.users[address])                            except:                  username = '匿名用户'              # 握手成功 分配线程进行监听              print u'\n用户: ',username+' 进入了房间',"IP地址为:",address                self.clients[address] = tcpClientSock              self.thrs[address] = threading.Thread(target=self.readMsg, args=[address])              self.thrs[address].start()              #print u"\n:",self.clients        def readMsg(self, address):                #print u"\n:",self.clients                if address not in self.clients:              return False            client = self.clients[address]            import select          time_out = 0        try:              username = unquote(self.users[address])                        except:              username = '匿名用户'        while 1:              # print(len(self.clients))              if address in self.stops:                  self.close_client(address)                  print u"\n",username + "已经离开了系统!IP:",address                  break                # 检测超时              if time_out >= config['TIME_OUT']:                  self.close_client(address)                  break                time_out += 5                infds, outfds, errfds = select.select([client, ], [], [], 5)              if len(infds) == 0:                  continue                time_out = 0              try:                  info = client.recv(1024)              except:                  self.close_client(address)                  break                if not info:                  continue                if info == 'quit':                  self.close_client(address)                  break              code_len = ord(info[1]) & 127              if code_len == 126:                  masks = info[4:8]                  data = info[8:]              elif code_len == 127:                  masks = info[10:14]                  data = info[14:]              else:                  masks = info[2:6]                  data = info[6:]              i = 0              raw_str = ""              for d in data:                  # print(masks, masks[i % 4])                  raw_str += chr(ord(d) ^ ord(masks[i % 4]))                  # print(raw_str)                  i += 1                # 获取到输入的数据 向所有的客户端发送              # 开启线程记录                if raw_str:                  t1 = threading.Thread(target=self.send_data, args=[raw_str, address])                  t1.start()        def send_data(self, data, address):          #import struct          #from urllib import unquote          try:              username = unquote(self.users[address])          except:              username = '匿名用户'          if data:              data = str('【'+username+' 说】:'+data)            print u"\n服务端发送的信息为:",data        else:              return False          token = "\x81"          length = len(data)          if length < 126:              token += struct.pack("B", length)          elif length <= 0xFFFF:              token += struct.pack("!BH", 126, length)          else:              token += struct.pack("!BQ", 127, length)            # struct为Python中处理二进制数的模块,二进制流为C,或网络流的形式。          data = '%s%s' % (token, data)          try:              for key, val in self.clients.iteritems():                  client = val                  try:                      client.send(data)                  except:                      self.close_client(key)          except:              pass        def close_client(self, address):        try:              username = unquote(self.users[address])          except:              username = '匿名用户'        try:              client = self.clients.pop(address)              self.stops.append(address)              client.close()              del self.users[address]          except:              pass            print u"\n用户:",username +"已经退出,IP为:",address    if __name__ == '__main__':      c = Server()      c.listen_client()  

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket</title>
<script src="js/jquery.js" type="text/javascript"></script>
<style>
* {
font-family: "微软雅黑";
margin: 0;
padding: 0;
}


html, body {
width: 100%;
height: 100%;
background: #000;
position: relative;
}


.msgInfo {
position: fixed;
right: 2%;
top: 2%;
height: 96%;
width: 20%;
background: #666;
}


.msgInfo .hd {
width: 100%;
text-align: center;
height: 40px;
line-height: 40px;
color: #fff;
background: #333;
}


.msgInfo .bd {
padding: 20px;
height: 100%;
overflow: auto;
color: #fff;
line-height: 30px;
}


.msgInfo .bd p {
margin: 5px 0;
}


.sendBox {
position: fixed;
left: 2%;
bottom: 2%;
width: 74%;
height: 10%;
background: #666;
overflow: hidden;
}


.sendBox textarea {
width: 90%;
height: 100%;
display: inline-block;
background: #666;
color: #fff;
border: none;
float: left;
}


.sendBox button {
width: 10%;
height: 100%;
display: inline-block;
background: #333;
cursor: pointer;
color: #fff;
border: none;
float: left;
}


.renBox {
margin-left: 2%;
margin-top: 2%;
width: 74%;
height: 84%;
position: relative;
overflow: hidden;
float: left;
}


.renBox .ren {
display: inline-block;
position: absolute;
left: 500px;
top: 500px;
}


.renBox .ren .renHead {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 10px;
background: #fff;
}


.renBox .ren .sayInfo {
color: #fff;
position: absolute;
top: -30px;
width: 200px;
left: -90px;
text-align: center;
}


.renBox div {
color: #fff;
margin-left: 100%;
width: 100%;
overflow: hidden;
height: 30px;
line-height: 30px;
font-size: 20px;
}


.firstStep {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
background: #000;
text-align: center;
}


.firstStep .firstName {
display: inline-block;
padding-top: 300px;
}


.firstStep .firstName .username {
width: 300px;
height: 40px;
border: 0;
padding: 0 10px;
}


.firstStep .firstName .btn {
width: 100px;
height: 40px;
border: 0;
background: #333;
color: #fff;
cursor: pointer;
}
</style>
<script>
var socket;


function init(username) {
var host = "ws://localhost:11011/name/" + username;
try {
socket = new WebSocket(host);
socket.onopen = function(msg) {
log('您已经进入聊天室')
};
socket.onmessage = function(msg) {
log(msg.data);
};
socket.onclose = function(msg) {
log("与服务器连接断开");
};
} catch (ex) {
log(ex);
}
$(".sendInfo").focus();
}


function send() {
var txt, msg;
txt = $(".sendInfo");
msg = txt.val();
if (!msg) {
alert("发送消息不能为空!");
return;
}
txt.val('');
txt.focus();
try {
socket.send(msg);
$('.sayInfo').html(msg)
//        log("我说:"+msg);  
} catch (ex) {
log(ex);
}
}


window.onbeforeunload = function() {
try {
socket.send('quit');
socket.close();
socket = null;
} catch (ex) {
log(ex);
}
};


function nameok() {
var _name = $('input[name="username"]').val();
if (!_name) {
alert('请给自己取个名字吧')
} else {
$('.firstStep').remove()
init(_name)
}
}


function log(msg) {
$('.msgInfo .bd').append('<p>' + msg + '</p>');


//动画  
var _html = $('<div>', {
'class' : 'showMsg'
});
_html.html(msg);
$('.renBox').append(_html);
_html.animate({
'marginLeft' : '-100%'
}, 10000, function() {
_html.remove()
})
}
function show(obj) {
obj.fadeIn()
}
function onkey(event) {
if (event.keyCode == 13) {
send();
}
}
</script>
<!--<link href="/static/css/css.css" type="text/css" rel="stylesheet" />  -->
</head>




<body>
<div class="renBox">
<!--<div class="ren">-->
<!--<span class="sayInfo"></span>-->
<!--<span class="renHead"></span>-->
<!--</div>-->
</div>
<div class="msgInfo">
<div class="hd">聊天记录</div>
<div class="bd"></div>
</div>
<div class="sendBox">
<textarea class="sendInfo"></textarea>
<button onclick="send()">发送</button>
</div>
</body>
<div class="firstStep">
<div class="firstName">
<input type="text" class="username" name="username"
placeholder="给自己取一个响亮的名字!" /><input type="button" class="btn"
onclick="nameok()" value="进入聊天" />
</div>
</div>
</html>