socket心跳+聊天

简单的小程序,vs2015编译通过

server

#include <tchar.h>
#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 2000 //端口号

typedef struct                    /* message structure */
{
    UINT16 type;
    char data[1024];
} msg_t;

#define MSG_TYPE1        1        /* application specific msg */
#define MSG_TYPE2        2        /* another one */
#define MSG_HEARTBEAT    3        /* heartbeat message */

#define T1        60        /* idle time before heartbeat */
#define T2        10        /* time to wait for response */
int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsa;
    //初始化套接字DLL
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("套接字初始化失败!");
        exit(-1);
    }

    SOCKET serverSocket;
    if ((serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("创建套接字失败!");
        exit(-1);
    }
    struct sockaddr_in serverAddress;
    memset(&serverAddress, 0, sizeof(sockaddr_in));
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    serverAddress.sin_port = htons(PORT);

    if (bind(serverSocket, (sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR)
    {
        printf("套接字绑定到端口失败!端口: %d\n", PORT);
        return -1;
    }
    //进入侦听状态
    if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR)
    {
        printf("侦听失败!");
        return -1;
    }

    printf("服务器端口: %d 正在监听......\n", PORT);
    //非阻塞
    ULONG nonblock = 1;
    if (ioctlsocket(serverSocket, FIONBIO, &nonblock) == SOCKET_ERROR)
    {
        printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
        return -1;
    }
    SOCKET acceptSocket;//用来和客户端通信的套接字
    struct sockaddr_in clientAddress;//用来和客户端通信的套接字地址
    memset(&clientAddress, 0, sizeof(clientAddress));
    int addrlen = sizeof(clientAddress);

    //fd_set fdRead;
    fd_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(serverSocket, &fdSocket);

    struct timeval tv;
    tv.tv_sec = T1 + T2;
    tv.tv_usec = 0;
    int missed_heartbeats = 0;

    msg_t msg;

    while (true)
    {
        fd_set fdRead = fdSocket;
        int nRet = select(serverSocket + 1, &fdRead, NULL, NULL, &tv);
        if (nRet < 0)
        {
            printf("select失败\n");
            break;
        }
        if (nRet == 0)        /* timed out */
        {
            if (++missed_heartbeats > 3)
                printf("连续三个心跳未收到,可能服务器已挂\n");
            printf("心跳未收到 #%d\n", missed_heartbeats);
            tv.tv_sec = T2;
            continue;
        }
        else
        {
            for (int i = 0; i < (int)fdSocket.fd_count; i++)
            {
                if (FD_ISSET(fdSocket.fd_array[i], &fdRead))
                {
                    if (fdSocket.fd_array[i] == serverSocket)
                    {
                        if ((acceptSocket = accept(serverSocket, (sockaddr*)&clientAddress, &addrlen)) == INVALID_SOCKET)
                        {
                            printf("接受客户端连接失败!");
                            return -1;
                        }
                        ULONG nonblock = 1;
                        if (ioctlsocket(acceptSocket, FIONBIO, &nonblock) == SOCKET_ERROR)
                        {
                            printf("Socket异步配置错误 %d\n", WSAGetLastError());
                            return -1;
                        }
                        FD_SET(acceptSocket, &fdSocket);
                        printf("建立连接成功\n");
                    }
                    else
                    {
                        //nRet--;
                        acceptSocket = fdSocket.fd_array[i];
                        //char buf[1024];
                        //int cnt=sizeof(buf);
                        memset(&msg, 0, sizeof(msg));
                        int bytes;
                        //if ((bytes = recv(acceptSocket, buf, 2, 0)) == SOCKET_ERROR)

                        if ((bytes = recv(acceptSocket, (char *)&msg, sizeof(msg), 0)) == SOCKET_ERROR)
                        {
                            printf("接收数据失败!\n");
                            return -1;
                        }
                        if (bytes > 0)
                        {
                            switch (ntohs(msg.type))
                            {
                            case MSG_TYPE1:
                            case MSG_TYPE2:
                                printf("有消息来自 %s: %s\n", inet_ntoa(clientAddress.sin_addr), msg.data);
                                if (send(acceptSocket, (char *)& msg, sizeof(msg_t), 0) == SOCKET_ERROR)
                                {
                                    printf("发送数据失败!");
                                    return -1;
                                }
                                missed_heartbeats = 0;
                                tv.tv_sec = T1 + T2;
                                break;
                            case MSG_HEARTBEAT:
                                printf("收到心跳\n");
                                bytes = send(acceptSocket, (char *)&msg, sizeof(msg), 0);
                                if (bytes < 0)
                                {
                                    printf("心跳回送失败\n");
                                    return -1;
                                }
                                missed_heartbeats = 0;
                                tv.tv_sec = T1 + T2;
                                break;
                            default:
                                printf("未知类型\n");
                                closesocket(fdSocket.fd_array[i]);
                                FD_CLR(fdSocket.fd_array[i], &fdSocket);
                                break;
                            }
                        }
                        else
                        {
                            closesocket(fdSocket.fd_array[i]);
                            FD_CLR(fdSocket.fd_array[i], &fdSocket);
                        }
                    }
                }
            }
        }
    }
    //清理套接字占用的资源
    WSACleanup();
    return 0;
}

client

#include <tchar.h>
#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>
#pragma comment(lib,"ws2_32.lib")
#define  PORT 2000

typedef struct                    /* message structure */
{
    UINT16 type;
    char data[1024];
} msg_t;

#define MSG_TYPE1        1        /* application specific msg */
#define MSG_TYPE2        2        /* another one */
#define MSG_HEARTBEAT    3        /* heartbeat message */

#define T1        6        /* idle time before heartbeat */
#define T2        1        /* time to wait for response */

DWORD WINAPI listenFunc(PVOID pvParam) {
    SOCKET sock = *((SOCKET*)pvParam);
    fd_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(sock, &fdSocket);
    struct timeval tv;
    tv.tv_sec = T1;
    tv.tv_usec = 0;
    int missed_heartbeats = 0;
    msg_t msg;
    int length;
    while (1)
    {
        fd_set fdRead = fdSocket;
        int nRet = select(sock + 1, &fdRead, NULL, NULL, &tv);
        if (nRet == 0)        /* timed out */
        {
            if (++missed_heartbeats > 3)
            {
                printf("连续三个心跳未收到,可能服务器已挂\n");
            }
            printf("发送心跳 #%d\n", missed_heartbeats);
            msg.type = htons(MSG_HEARTBEAT);
            if (send(sock, (char*)&msg, sizeof(msg), 0) == SOCKET_ERROR)
            {
                printf("发送数据失败!");
                return -1;
            }
            tv.tv_sec = T2;
            continue;
        }
        else
        {
            memset(&msg, 0, sizeof(msg));
            int bytes;
            if ((bytes = recv(sock, (char *)&msg, sizeof(msg), 0)) == SOCKET_ERROR)
            {
                printf("接收数据失败!\n");
                return -1;
            }
            if (bytes > 0)
            {
                switch (ntohs(msg.type))
                {
                case MSG_TYPE1:
                case MSG_TYPE2:
                    printf("有消息来: %s\n", msg.data);
                    break;
                case MSG_HEARTBEAT:
                    printf("收到心跳\n");
                    break;
                default:
                    printf("未知类型\n");
                    closesocket(sock);
                    FD_CLR(sock, &fdSocket);
                    break;
                }
                missed_heartbeats = 0;
                tv.tv_sec = T1 + T2;
            }
            else
            {
                closesocket(sock);
                FD_CLR(sock, &fdSocket);
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsa;
    //初始化套接字DLL
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("套接字初始化失败!");
        return -1;
    }

    SOCKET sock;
    if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("创建套接字失败!");
        return -1;
    }
    //char ipaddr[100];
    //printf("请输入对方ip地址:");
    //gets(ipaddr);
    struct sockaddr_in serverAddress;
    memset(&serverAddress, 0, sizeof(sockaddr_in));
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    serverAddress.sin_port = htons(PORT);

    if (connect(sock, (sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR)
    {
        printf("建立连接失败!");
        return -1;
    }

    ULONG nonblock = 1;
    if (ioctlsocket(sock, FIONBIO, &nonblock) == SOCKET_ERROR)
    {
        printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
        return -1;
    }

    _beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))listenFunc, &sock, 0, NULL);

    msg_t msg;
    memset(&msg, 0, sizeof(msg));

    while (true)
    {
        gets_s(msg.data);
        msg.type = htons(MSG_TYPE1);
        if (send(sock, (char*)&msg, sizeof(msg), 0) == SOCKET_ERROR)
        {
            printf("发送数据失败!");
            return -1;
        }
    }
    //清理套接字占用的资源
    WSACleanup();
    return 0;
}
时间: 2024-10-26 14:38:47

socket心跳+聊天的相关文章

web socket 心跳包的实现方案

web socket 心跳包的实现方案05/30/2010 现在网络环境错综复杂,socket心跳包是获得健康强壮的连接的有效解决方案,今天,我们就在web socket中实现心跳包方案,是的,尽管我们只是做一个简单的聊天室,但我们让他稳定可靠一些一点也没有错. 我的心跳包方案很是简单,原理就是间隔发送心跳包数据给服务器,服务器在一定时间内发回心跳包响应,对比超时限定,如果超过设定的超时时间,则认为当前与服务器的websocket连接已经断开,关闭当前web socket连接,善后处理,例如重新

[转] Socket心跳包异常检测的C语言实现,服务器与客户端代码案例

转载自:zxh2075的专栏 在Socket心跳机制中,心跳包可以由服务器发送给客户端,也可以由客户端发送给服务器,不过比较起来,前者开销可能较大.本文实现的是由客户端给服务器发送心跳包,服务器不必返回应答包,而是通过判断客户在线会话记录中的计数标志值来实现心跳异常的检测,以此决定客户端是否已经断开连接以及删除其在线会话记录. 基本思路: ①客户端定时给服务器发送心跳包(案例中定时时间为3秒): ②服务器创建一个心跳检测的线程,线程中每隔3秒对用户在线会话记录中的计数器进行加1操作(初始值为0)

nodejs+socket.io聊天室

nodejs+socket.io 聊天室 Node.js v0.12.6 Socket.io v1.3.5 RequireJS v2.1.18 Materialize v0.97.0 聊天室演示地址 项目地址 版权声明:本文为博主原创文章,未经博主允许不得转载.

Socket.IO聊天室

小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ Socket.IO聊天室 简介:Socket.IO实现了实时双向的基于事件的通讯机制.旨在让各种浏览器与移动设备上实现实时app功能,模糊化各种传输机制.下面我们使用Node.js和Socket.IO来做一个简单的聊天室.一.初始化项目 (这个是在实验楼网站的虚拟平台需要实现的~可自动略过这一环节,

windows phone 8.1开发:socket通信聊天

本例用WPF程序做服务器端,windows phone程序做客户端.我们使用基于UDP协议的Socket通信.更多关于socket信息请查看:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket(v=vs.110).aspx 我们使用DatagramSocket类完成UDP通信功能. 具体代码如下:(前台代码就不帖出来了,下面只给出后台代码和一些注释.完整源代码会在论坛发出来,地址在文章最后.) socket通信聊天w

Socket心跳包机制

Socket心跳包机制 分类: C++ MFC/C#/Qt TCP/IP/UDP等网络编程2012-12-10 20:42 20431人阅读 评论(4) 收藏 举报 心跳包的发送,通常有两种技术方法1:应用层自己实现的心跳包 由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线:同样,如果客户端在一定时间

Python Socket 编程——聊天室示例程序

原文:Python Socket 编程--聊天室示例程序 上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的理解. 聊天室程序需求 我们要实现的是简单的聊天室的例子,就是允许多个人同时一起聊天,每个人发送的消息所有人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天.如下图: 图来自:http://www.ibm.com/de

【转载】TCP socket心跳包示例程序

在做游戏开发时,经常需要在应用层实现自己的心跳机制,即定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性. 在TCP socket心跳机制中,心跳包可以由服务器发送给客户端,也可以由客户端发送给服务器,不过比较起来,前者开销可能更大.-- 这里实现的是由客户端给服务器发送心跳包,基本思路是: 1) 服务器为每个客户端保存了IP和计数器count,即map<fd, pair<ip, count>>.服务端主线程采用 select 实现多路IO复用,监听新连

Python Socket 编程——聊天室演示样例程序

上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket 编程的理解. 聊天室程序需求 我们要实现的是简单的聊天室的样例,就是同意多个人同一时候一起聊天.每一个人发送的消息全部人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天.例如以下图: 图来自:http://www.ibm.com/developerworks/linux/tu