构建在IOS中使用node.js服务器的聊天应用程序

时间:2014-09-13 07:25:51

标签: ios node.js socket.io chat

我正在尝试构建一个在socket.io上使用node.js的iPhone(原生)聊天应用。

在IOS上创建聊天应用程序的最佳方法是什么

是否有任何方法可以在IOS中使用node.js服务器创建聊天应用程序

有人可以给我建议吗?

谢谢你的建议

3 个答案:

答案 0 :(得分:6)

你可以使用Socket.io与iOS / Android和HTML创建聊天应用程序!

有两种方法可以做到这一点!

i)使用Socket.io实现自己的套接字通信,(这是难以理解的,因为你需要自己编写大部分网络实现!)

Socket.io将作为流接口,您需要从iOS连接!

您可以参考iOS开发指南,了解如何实现流!

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/UsingSocketsandSocketStreams.html

有一个活跃的主题也在讨论这个问题!

iPhone Objective-C socket communication with Socket.IO

ii)使用人们为iOS制作的现有库或包装器,您可以在下面找到链接!

这个库主要完成了网络部分,你只需要实现你的应用程序逻辑!

的iOS

https://github.com/pkyeck/socket.IO-objc

的Android

https://github.com/nkzawa/socket.io-client.java

首先从库开始然后尝试自己实现,这对你有好处! :))

答案 1 :(得分:3)

我建议遵循:

  1. 使用node.js和NOSQL数据库(在我的示例中为CouchDb)在服务器上开发HTML5应用程序
  2. 不要将socket.io用于您的第一个游乐场,因为它很复杂。你必须先了解websockets。
  3. 不要给预先准备好的框架和大量代码带来负担。您需要一个清晰,简单的代码,以便稍后进行修改。您需要完全控制和理解您拥有的代码。

    我附上了工作样本(感谢Ales Smodis)。要使示例工作正常,您需要安装2个node.js数据包:

    npm install websocket
    npm install nano 
    

    您需要创建数据库并将至少一个用户插入CouchDb数据库:

    curl -X PUT http://localhost:5984/chatroom
    curl -X PUT -H 'Content-Type: application/json' --data '{"username":"john","password":"john"}' http://localhost:5984/chatroom/john
    

    $(document).ready(function () {
    
        var connection,
            username = 'Tester',
            password = 'Tester',
            historyCounter = 0,
            members = {},
            // displays
            jqLogin = $('#login'),
            jqChatroom = $('#chatroom'),
            // login display components
            jqWaiting = $('#waiting'),
            jqNickname = $('#nickname'),
            jqPassword = $('#password'),
            // chat display components
            jqHistory = $('#history'),
            jqMembers = $('#members'),
            jqLine = $('#line');
    
        function addLine(nick, line) {
            var jq = $('<p><span class="nick"></span><span class="line"></span></p>'),
                jqNick = jq.find('.nick'),
                jqLine = jq.find('.line'),
                i, lines;
            jqNick.text(nick ? nick + ': ' : '*** ');
            jqLine.text(line);
            jqHistory.append(jq);
            historyCounter++;
            for (lines = jqHistory.children(), i = 0; historyCounter > 100; i++, historyCounter--) {
                $(lines[i]).remove();
            }
        }
    
        function addMsg(msgObj) {
            var msgHandler = states[activeState].messageHandlers[msgObj.type] || function () { addLine(null, 'Neveljaven paket tipa ' + msgObj.type); };
            msgHandler(msgObj);
        }
    
        function clearMembers() {
            var nickname;
            for (nickname in members) {
                members[nickname].remove();
                delete members[nickname];
            }
            jqMembers.empty(); // just in case
        }
    
        function addMember(nickname) {
            var jq = $('<li></li>');
            jq.text(nickname);
            jqMembers.append(jq);
            members[nickname] = jq;
        }
    
        function removeMember(nickname) {
            if (nickname in members) {
                members[nickname].remove();
                delete members[nickname];
            }
        }
    
        function connect () {
            connection = new WebSocket('ws://127.0.0.1:8080');
    
            connection.onopen = function () {
                states[activeState].onopen();
            };
    
            connection.onmessage = function (message) {
                try {
                    addMsg(JSON.parse(message.data));
                }
                catch (e) {
                    addLine(null, 'Exception while handling a server message: ' + e.toString());
                }
            };
    
            connection.onclose = function () {
                states[activeState].onclose();
            };
        }
    
        function loginKeypress(event) {
            if (13 !== event.keyCode) return;
            username = jqNickname.val();
            password = jqPassword.val();
            if (!username) jqNickname[0].focus();
            else if (!password) jqPassword[0].focus();
            else {
                jqWaiting.css('display', '');
                jqNickname.unbind('keydown', loginKeypress);
                jqPassword.unbind('keydown', loginKeypress);
                connect();
            }
        }
    
        function inputKeypress(event) {
            var line;
            if (13 === event.keyCode) {
                line = jqLine.val();
                if (line.length === 0) return;
                jqLine.val('');
                connection.send(JSON.stringify({ 'type': 'line', 'line': line }));
            }
        }
    
        var states = {
                'login': {
                    'start': function () {
                        jqChatroom.css('display', 'none');
                        jqWaiting.css('display', 'none');
                        jqLogin.css('display', '');
                        jqNickname.val('');
                        jqPassword.val('');
                        jqNickname[0].focus();
                        activeState = 'login';
                        jqNickname.bind('keydown', loginKeypress);
                        jqPassword.bind('keydown', loginKeypress);
                    },
                    'onopen': function () {
                        connection.send(JSON.stringify({ 'type': 'login', 'username': username, 'password': password }));
                    },
                    'messageHandlers': {
                        'state': function (msgObj) {
                            var i, history, users;
                            states.chat.start();
                            history = msgObj.history;
                            jqHistory.empty();
                            historyCounter = 0;
                            for (i = 0; i < history.length; i++) addMsg(history[i]);
                            users = msgObj.users;
                            clearMembers();
                            for (i = 0; i < users.length; i++) addMember(users[i]);
                        }
                    },
                    'unhandledMessage': function (msgObj) {
                        connection.close(4000, 'Unhandled message type');
                    },
                    'onclose': function () {
                        states.login.start();
                    }
                },
    
                'chat': {
                    'start': function () {
                        jqLogin.css('display', 'none');
                        jqWaiting.css('display', 'none');
                        jqChatroom.css('display', '');
                        jqHistory.empty();
                        historyCounter = 0;
                        activeState = 'chat';
                        jqLine.bind('keydown', inputKeypress);
                    },
                    'onopen': function () {
                        connection.close(4001, 'Connection opened while chatting');
                    },
                    'messageHandlers': {
                        'line': function (msgObj) {
                            addLine(msgObj.nick, msgObj.line);
                        },
                        'join': function (msgObj) {
                            addLine(null, 'Priklopil: ' + msgObj.nick);
                            addMember(msgObj.nick);
                        },
                        'leave': function (msgObj) {
                            addLine(null, 'Odklopil: ' + msgObj.nick);
                            removeMember(msgObj.nick);
                        }
                    },
                    'unhandledMessage': function (msgObj) {
                        connection.close(4000, 'Unhandled message type');
                    },
                    'onclose': function () {
                        addLine(null, 'Connection closed');
                        jqLine.unbind('keydown', inputKeypress);
                    }
                }
            },
            activeState = 'login';
    
        states.login.start();
    });
    // node.js code
    var http = require('http'),
        url = require('url'),
        path = require('path'),
        fs = require('fs'),
        nano = require('nano')('http://localhost:5984'),
        chatroomDb = nano.use('chatroom'),
        websocket = require('websocket'),
        chatHistory = [],
        activeUsers = {};
    
    var filesDir = path.join(process.cwd(), 'web');
    
    var mimeTypes = {
        '.html': 'text/html',
        '.css': 'text/css',
        '.js': 'text/javascript'
    };
    
    var getContentType = function (extension) {
        var mimeType = mimeTypes[extension];
        return mimeType ? mimeType : 'application/octet-stream';
    };
    
    var server = http.createServer(function (request, response) {
        var relativePath = url.parse(request.url).pathname,
            absolutePath = path.join(filesDir, relativePath);
        var handler = function (err, stats) {
            if (stats) {
                if (stats.isDirectory()) {
                    absolutePath = path.join(absolutePath, 'index.html');
                    fs.stat(absolutePath, handler);
                    return;
                }
                if (stats.isFile()) {
                    response.writeHead(200, getContentType(path.extname(absolutePath)));
                    var stream = fs.createReadStream(absolutePath);
                    stream.pipe(response);
                    return;
                }
            }
            response.writeHead(404, {'Content-Type': 'text/plain'});
            response.write('Not found\r\n');
            response.end();
        };
        console.log('HTTP request for ' + relativePath);
        fs.stat(absolutePath, handler);
    });
    server.listen(8080, function () {});
    
    wsServer = new websocket.server({
        'httpServer': server
    });
    
    function addLine (type, nick, line) {
        var msg = { 'type': type, 'nick': nick, 'line': line },
            jsonMsg = JSON.stringify(msg),
            username;
        chatHistory.push(msg);
        while (chatHistory.length > 100) chatHistory.shift();
        for (username in activeUsers) {
            activeUsers[username].sendMessage(jsonMsg);
        }
    }
    
    wsServer.on('request', function (request) {
        console.log('New websocket connection from ' + request.origin);
        // TODO: verify that request.origin is our web site
    
        var connection = request.accept(null, request.origin);
    
        var username = null;
    
        connection.on('message', function (message) {
            if (message.type !== 'utf8') {
                console.log('Refusing a non-utf8 message');
                return;
            }
            console.log('Processing message: ' + message.utf8Data);
            try {
                var m = JSON.parse(message.utf8Data);
                switch (m.type) {
    
                    case 'login':
                        chatroomDb.get(m.username, function (err, body) {
                            if (err || (body.password !== m.password)) {
                                connection.close();
                                return;
                            }
                            username = m.username;
                            addLine('join', username, null);
                            activeUsers[username] = {
                                'sendMessage': function (jsonMsg) {
                                    connection.sendUTF(jsonMsg);
                                }
                            };
                            var users = [], u;
                            for (u in activeUsers) users.push(u);
                            connection.sendUTF(JSON.stringify({ 'type': 'state', 'history': chatHistory, 'users': users }));
                        });
                        break;
    
                    case 'line':
                        if (!username) {
                            connection.close();
                            break;
                        }
                        addLine('line', username, m.line);
                        break;
                }
            }
            catch (e) {
                console.log(e);
            }
        });
    
        connection.on('close', function (connection) {
            console.log('Connection closed');
            if (username) {
                delete activeUsers[username];
                addLine('leave', username, null);
            }
        });
    });
    
    console.log('Server running');
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Chatroom</title>
          <style>
            html, body {
        width: 100%;
        height: 100%;
        padding: 0;
        border: none;
        margin: 0;
    }
    
    #heading {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 30px;
        margin: 0;
        padding: 0;
        line-height: 30px;
        text-align: center;
        font-size: 20px;
        background-color: green;
    }
    
    #outer {
        position: absolute;
        top: 30px;
        bottom: 0;
        left: 0;
        right: 0;
        margin: 20px;
        min-height: 400px;
        min-width: 400px;
        background-color: lime;
    }
    
    #inner {
        height: 100%;
        background-color: #ffc0cb;
    }
    
    #chat {
        position: absolute;
        top: 0;
        left: 0;
        right: 200px;
        bottom: 0;
        background-color: #ffd700;
    }
    
    #members {
        position: absolute;
        top: 0;
        right: 10px;
        width: 180px;
        bottom: 0;
        background-color: #ff00ff;
        list-style-type: none;
        padding: 10px;
        padding: 0;
        border: none;
    }
    
    #history {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 2em;
        right: 0;
        background-color: #00ffff;
        padding: 10px;
    }
    
    #input {
        position: absolute;
        height: 2em;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #90ee90;
        line-height: 2em;
    }
    
    #line {
        width: 100%;
        margin: 0;
        border: none;
        padding: 0;
    }
    
    #history > p {
        margin: 2px;
    }
    
    .nick {
        white-space: pre;
        display: table-cell;
    }
    
    .line {
        display: table-cell;
    }
    
    #login {
        height: 100%;
        display: table;
        margin: 0 auto;
    }
    #login > .svg {
        vertical-align: middle;
        display: table-cell;
    }
    #login-wrapper1 {
        display: table;
        height: 100%;
        width: 100%;
    }
    #login-wrapper2 {
        display: table-cell;
        vertical-align: middle;
    }
    #login-table {
        margin: 0 auto;
    }
    #login-table .label {
        text-align: right;
    }
    
    #waiting {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        opacity: 0.3;
    }
    
           </style> 
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
            <script src="client.js"></script>
        </head>
        <body>
            <div id="login">
                <div class="svg">
    
                    <svg
                        xmlns="http://www.w3.org/2000/svg"
                        xmlns:xlink="http://www.w3.org/1999/xlink"
                        viewBox="0 0 400 400"
                        width="400"
                        height="400">
                        <defs>
                            <path id="curved-text" d="M0,0 c 50 -50 150 -50 200 0" />
                        </defs>
                        <g>
                            <text
                                transform="translate(-100,40)"
                                font-weight="bold"
                                font-variant="small-caps"
                                font-family="Arial sans-serif"
                                font-size="30"
                                fill="none"
                                stroke="orange"
                                text-anchor="middle">
                                <textPath xlink:href="#curved-text" startOffset="50%">Chatroom</textPath>
                            </text>
                            <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="5s" fill="remove" additive="sum" repeatCount="indefinite" />
                            <animateMotion dur="10s" repeatCount="indefinite" path="M100,200 a100,100 0 1 1 200,0 a100,100 0 1 1 -200,0" />
                        </g>
                        <foreignObject
                            x="0"
                            y="0"
                            width="400"
                            height="400"
                            style="height:400px;">
    
                            <div xmlns="http://www.w3.org/1999/xhtml" id="login-wrapper1">
                                <div id="login-wrapper2">
                                    <table id="login-table">
                                        <tbody>
                                            <tr>
                                                <td class="label">Vzdevek:</td><td><input type="text" id="nickname" /></td>
                                            </tr>
                                            <tr>
                                                <td class="label">Geslo:</td><td><input type="password" id="password" /></td>
                                            </tr>
                                        </tbody>
                                    </table>
                                </div>
                            </div>
    
                        </foreignObject>
                    </svg>
    
                </div>
            </div>
    
            <div id="chatroom" style="display:none;">
                <h1 id="heading">Chatroom</h1>
    
                <div id="outer">
                    <div id="inner">
                        <div id="chat">
                            <div id="history">
                                <p><span class="nick">Matej: </span><span class="line">Hi</span></p>
                                <p><span class="nick">Borut: </span><span class="line">How are you?</span></p>
                                <p><span class="nick">Martina: </span><span class="line">Ok, thanks!</span></p>
                            </div>
                            <div id="input"><input id="line" type="text"></div>
                        </div>
                        <ul id="members">
                            <li>Matej</li>
                            <li>Borut</li>
                            <li>Martina</li>
                        </ul>
                    </div>
                </div>
            </div>
    
            <div id="waiting" style="display:none;"></div>
    
        </body>
    </html>

答案 2 :(得分:0)

如果您正在评估选项,请查看Twilio的IP消息:

https://www.twilio.com/docs/tutorials/walkthrough/ip-chat/ios/swift#0

上面的Swift for iOS教程(也可用于Objective-C)允许您使用本机SDK,而服务器端应用程序(yours in Node.js)生成用户访问令牌以连接到API。

该代码引导您加入频道,创建频道和发送消息。

注意:我的确适用于Twilio 。这个快速示例应用程序至少应该帮助您确定哪种功能最适合您。