聊天web项目

# coding: utf-8  
  
from socket import *  
import json, time, threading
import struct
from urllib import unquote

config = {  
    '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 οnclick="send()">发送</button>
</div>
</body>
<div class="firstStep">
<div class="firstName">
<input type="text" class="username" name="username"
placeholder="给自己取一个响亮的名字!" /><input type="button" class="btn"
οnclick="nameok()" value="进入聊天" />
</div>
</div>
</html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值