1.該系統(tǒng)基于nodeJs,electron旨在開發(fā)一個桌面端的簡單聊天系統(tǒng)(1對1)
2.基于nodeJs的socket編程
思路:
首先需要一個服務(wù)器,用來做中轉(zhuǎn)服務(wù),并做一些邏輯判斷麦射,從而達(dá)到一對一聊天的目的
客戶端只需連接服務(wù)器,制定一定的數(shù)據(jù)格式進(jìn)行發(fā)送數(shù)據(jù)即可
具體的界面則用electron來處理
服務(wù)器代碼:
var net = require('net'); // 使用net模塊(創(chuàng)建TCP的SOCKET)
var PORT = 8080; //端口參數(shù)
var server = net.createServer(); //創(chuàng)建一個tcp的服務(wù)器
var room = [];//定義一個聊天室的數(shù)組
//on函數(shù)作用是監(jiān)聽函數(shù)摹迷,第一個參數(shù)為監(jiān)聽的數(shù)據(jù)名宵凌,第二個是監(jiān)聽到后執(zhí)行的回調(diào)函數(shù)
server.on('connection', function (socket) { //監(jiān)聽connect連接,即當(dāng)客戶端發(fā)起鏈接時隅居,服務(wù)器捕獲該鏈接钠至,執(zhí)行后面的函數(shù)
//客戶端和服務(wù)器完成TCP鏈接后 會生成一個socket,這里作為回調(diào)的參數(shù)獲取
console.log("new connection" + socket.remoteAddress + ':' + socket.remotePort);
socket.on('data', function (data) { //給socket 添加監(jiān)聽事件胎源,即當(dāng)客戶端和服務(wù)器連接上后 進(jìn)行的傳輸皆用該socket 進(jìn)行
var data = JSON.parse(data.toString().trim()); //JSON.parse 可將json字符串轉(zhuǎn)換為json對象 【socket傳輸?shù)臅r候只支持字符串/二進(jìn)制】
//分別獲取data內(nèi)的內(nèi)容
var from = data.from;
var to = data.to;
var msg = data.msg;
//定制聊天室數(shù)組內(nèi)存儲的json的格式棉钧,用來限制1對1聊天
var singelRoom = {
"name1": from,
"name1S": socket,
"name2": to
}
//如果聊天室為空 直接放入第一個單人聊天室json數(shù)據(jù)
if (room.length == 0) {
room.push(singelRoom);
}
var flag = 0;
// 遍歷聊天室中的內(nèi)容
for (var i in room) {
//聊天室中存的是自己和對方的聊天信息 則執(zhí)行
if ((room[i].name1 == from && room[i].name2 == to) || (room[i].name1 == to && room[i].name2 == from)) {
flag = 1;
//準(zhǔn)確的存入自己的socket
if(room[i].name1 == from){
room[i].name1S = socket;
}
if(room[i].name2 == from){
room[i].name2S = socket;
}
// 如果當(dāng)前socket 和 單人聊天室json數(shù)據(jù)的信息一致 則獲取第一方的socket
if (room[i].name1S == socket) {
if (room[i].name2S != null) {
var toSocket = room[i].name2S;
toSocket.write(msg);
} else {
//對方socket為空 說明對方?jīng)]有發(fā)送data信息,這里沒有保存他的socket信息(可以理解為對方發(fā)送消息才算上線涕蚤,這里就算未上線)
socket.write("等待對方上線");
}
} else {
room[i].name2S = socket;
if (room[i].name1S != null) {
var toSocket = room[i].name1S;
toSocket.write(msg);
} else {
socket.write("等待對方上線");
}
}
}
}
if (flag == 0) {
//console.log("first");
room.push(singelRoom);
//console.log(room.length);
socket.write("等待對方上線");
}
});
//監(jiān)聽客戶端的close事件(即下線)
socket.on('close', function () {
//從聊天室中找到當(dāng)前的socket 并把它置為空
if(socket!=null){
for (var i in room) {
if(room[i].name1S==socket){
room[i].name1S=null;
}
else if(room[i].name2S==socket){
room[i].name2S=null;
}
else{
break;
}
}
}
console.log('A client closed');
});
//監(jiān)聽socket錯誤,并打印
socket.on('error',(err)=>{
console.log("下線請求宪卿!"+err);
});
});
server.on('error', function (err) {
console.log('server error:', err.message);
});
server.on('close', function () {
console.log('server closed');
});
//服務(wù)器監(jiān)聽地址 0.0.0.0 端口8080
server.listen(PORT, '0.0.0.0');
客戶端:
頁面(index.html):[這里用的electron來處理的诵,這里只涉及index.html和相關(guān)的js,具體main.js的知識請大家查看electron相關(guān)的文檔]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>聊天室</title>
<link rel="stylesheet" href="./lib/stone.css">
<style>
body{
overflow: hidden;
}
h1{
font-size: 25px;
font-weight: bold;
}
input{
border:1px solid gray;
}
textarea{
outline: 0;
height: 128px;
border-top: 1px solid gray;
border-bottom: 1px solid gray;
width: 96%;
padding: 20px;
margin: 0 auto;
resize : none;
}
#content {
display: none;
}
#start{
display: none;
}
#welcome{
width: 100%;
height: 600px;
text-align: center;
color: white;
}
#welcome h1{
padding-top: 200px;
}
#welcome h4{
margin-top: 150px;
font-size: 14px;
}
#welcome h5{
margin-top: 5px;
font-size: 12px;
}
#start_box{
width: 400px;
height: 200px;
margin: 0 auto;
text-align: center;
}
#start_box h1{
padding-top: 50px;
margin-bottom: 100px;
}
#start_box p{
padding-bottom: 11px;
}
#start_box input{
height: 30px;
text-align: center;
}
#sendBtn{
outline: 0;
width:110px;
height: 40px;
line-height: 40px;
text-align: center;
}
#chatMsg{
width: 90%;
margin: 0 auto;
padding: 20px;
height: 290px;
overflow: auto;
}
#sendMsg{
float: right;
position: relative;
right: 10px;
width: 80px;
height: 30px;
line-height: 30px;
border: 1px solid grey;
}
From,To{
width:100%;
font-size: 12px;
margin-bottom: 5px;
}
.title{
font-weight: bold;
font-size: 16px;
}
</style>
</head>
<body>
<div id="welcome" class="lightBlue">
<h1>局 域 網(wǎng) 聊 天 室</h1>
<h4>正在進(jìn)入...</h4>
<h5>by 袁浩宇/李雪可(echoun)</h5>
</div>
<div id="start">
<div id="start_box">
<h1 class="tc">歡迎使用聊天室軟件</h1>
<p>請輸入當(dāng)前用戶號碼:</p><input type="text" id="from"><br/><br/>
<p>請輸入對方用戶號碼:</p><input type="text" id="to"><br/><br/>
<button id="sendBtn" class="Sbs">開始聊天</button>
</div>
</div>
<div id="content">
<div id="chatMsg"></div>
<div id="txt">
<textarea name="" id="msg"></textarea><br/>
<button id="sendMsg" onclick="sendMsg()">發(fā)送</button>
</div>
</div>
</body>
<script>
// You can also require other files to run in this process
require('./client.js')
</script>
</html>
邏輯:(client.js)
var net = require('net');
var PORT = 8080;
var From, To;
var Msg = null;
//顯示邏輯(4s后welcome的div 隱藏 start的div 顯示)
setTimeout(function () {
document.getElementById("welcome").style.display = "none";
document.getElementById("start").style.display = "block";
}, 4000)
//創(chuàng)建客戶端(需要制定port,即服務(wù)器監(jiān)聽的port 還有就是host參數(shù)展氓,這里我沒有寫 默認(rèn)為127.0.0.1 如果要局域網(wǎng)通信則寫服務(wù)器的地址估蹄,其他的默認(rèn)值具體可以去看官方文檔)
var client = net.connect({port: PORT}, function () {
document.getElementById('sendBtn').onclick = function () {
//獲取from 和 to 的值
From = document.getElementById("from").value;
To = document.getElementById("to").value;
if (From == To && From != "") {
alert("請輸入不一樣的號碼!");
return 0;
}
if (From == "" || To == "") {
alert("輸入不能為空");
return 0;
}
document.title = From + '正在與' + To + '通話';
document.getElementById("start").style.display = "none";
document.getElementById("content").style.display = "block";
}
document.getElementById('sendMsg').onclick = function () {
var myDate = new Date();
Msg = document.getElementById("msg").value;
if(Msg==""){
alert("輸入空值給你的小伙伴看瘪阁,并沒有什么意義哦!");
return 0;
}
//定義要發(fā)送數(shù)據(jù)的格式
var send = {
from: From,
to: To,
msg: Msg
};
client.on('error', function (err) {
alert('請檢查服務(wù)器是否正確啟動邮偎!');
console.log(err);
});
//將自己發(fā)出的數(shù)據(jù) 顯示在頁面中
var textNodeTo = document.createElement('div');
textNodeTo.innerHTML = '<p class="title">' + From + ' - 【Time ' + myDate.getHours() + ':' + myDate.getMinutes() + ':' + myDate.getSeconds() + '】</p>' + '<p>' + Msg.toString() + '</p>';
textNodeTo.className = 'To tr tblue';
var parentNode = document.getElementById("chatMsg");
parentNode.appendChild(textNodeTo);
// socket的寫操作管跺,注意傳輸時轉(zhuǎn)換成字符型
client.write(JSON.stringify(send));
document.getElementById("msg").value = null;
};
});
//監(jiān)聽data,及獲取服務(wù)器發(fā)來的信息
client.on('data', function (data) {
// 顯示在頁面上
var myDate = new Date();
var textNodeFrom = document.createElement('div');
textNodeFrom.innerHTML = '<p class="title">' + To + ' - 【Time ' + myDate.getHours() + ':' + myDate.getMinutes() + ':' + myDate.getSeconds() + '】</p>' + '<p>' + data.toString() + '</p>';
textNodeFrom.className = 'From tl tgreen';
var parentNode = document.getElementById("chatMsg");
parentNode.appendChild(textNodeFrom);
});
client.on('end', function () {
console.log('Disconnected from server');
process.exit();
});
總體來說這里還是講的比較啰嗦啦禾进,如果想直接使用豁跑,可以通過下面的傳送門。
傳送門:https://github.com/yuanhaoyu/Chatroom (覺得不錯可以star 支持一哈)