IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]socket消息流程介绍及其C代码实现

    zhouzxi发表于 2015-06-08 19:11:42
    love 0

    在实际的软件开发工作中,经常会涉及到socket编程,也就是利用socket来完成消息的交互和命令的执行。本文通过一个C程序来讲解Linux下socket的整个消息执行流程。

    C程序示例

    /**********************************************************************
    * 版权所有 (C)2015, Zhou Zhaoxiong。
    *
    * 文件名称:TestSocket.c
    * 文件标识:无
    * 内容摘要:测试socket从创建到结束的整个过程
    * 其它说明:无
    * 当前版本: V1.0
    * 作   者: Zhou Zhaoxiong
    * 完成日期: 20150608
    *
    **********************************************************************/
    #include 
    #include 
    #include 
    #include 
    #include in.h><span>
    #include socket.h><span>
    
    // 宏定义
    #define INVALID_SOCKET  -1
    #define SOCKET_ERROR    -1
    #define BUFFER_LEN      1024
    #define SERVERPORT      8999
    #define IPADDR          "10.116.32.10"
    
    // 重定义数据类型
    typedef unsigned char  UINT8;
    typedef signed   int   INT32;
    typedef unsigned int   UINT32;
    typedef          INT32 SOCKET;
    
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr    *PSOCKADDR;
    
    // 全局变量
    UINT8 g_iStart  = 0;
    UINT8 g_iFinish = 0;
    
    
    /**********************************************************************
    * 功能描述:主函数
    * 输入参数:无
    * 输出参数:无
    * 返 回 值:无
    * 其它说明:无
    * 修改日期         版本号        修改人           修改内容
    * -------------------------------------------------------------------
    * 20150608        V1.0     Zhou Zhaoxiong        创建
    ***********************************************************************/
    INT32 main()
    {
        INT32  iRet     = -1;
        INT32  status   = 0;
        INT32  iTempVar = 0;
        UINT32 iLenth   = 0;
    
        UINT8 szBuffer[BUFFER_LEN] = {0};
    
        SOCKET      sockefd        = INVALID_SOCKET;
        SOCKET      clientSocketfd = {0};
        SOCKADDR_IN local_address  = {0};
        SOCKADDR_IN client_addrss  = {0};
    
        pthread_t tid = pthread_self();
    
        while (1)
        {
            // 创建socket
            close(sockefd);
            sockefd = socket(AF_INET, SOCK_STREAM, 0);
            if (INVALID_SOCKET == sockefd)
            {
                continue;
            }
    
            // 绑定指定IP地址和端口
            local_address.sin_family     = AF_INET;
            local_address.sin_port       = htons(SERVERPORT);
            local_address.sin_addr.s_addr= inet_addr(IPADDR);
    
            status   = SOCKET_ERROR;
            iTempVar = 1;
    
            if (setsockopt(sockefd, SOL_SOCKET, SO_REUSEADDR, (int *)&iTempVar;, sizeof(iTempVar)) == -1)
            {
                printf("setsockopt SO_REUSEADDR FAILED! ERROR[%d] ERRORINFO[%s]\n", errno, strerror(errno));
    
                close(sockefd);;
                continue;    
            }
    
            status = bind(sockefd, (PSOCKADDR)&local;_address, sizeof(SOCKADDR_IN));    // 绑定指定IP地址和端口
            if (status == SOCKET_ERROR)
            {
                close(sockefd);;
                printf("FAILED to bind ipaddr:%s!\n", IPADDR);
    
                continue; 
            }
            else
            {
                printf("Succeeded to bind ipaddr:%s, port:%d!\n", IPADDR, SERVERPORT);
                break;
            }
        }
    
        // 启动监听
        iRet = listen(sockefd, 10);
        if (iRet < 0)
        {
            printf("FAILED to stratup the listener!\n");
    
            return -1;
        }
    
        // 循环从监听队列中获取
        while (1)
        {
            iLenth = sizeof(client_addrss);
            clientSocketfd = accept(sockefd, (struct sockaddr *)&client;_addrss, &iLenth;);
            if (clientSocketfd == INVALID_SOCKET)
            {
                printf("The client socket is invalid!\n");
    
                continue;
            }
            printf("------------------------------------------\n");
            printf("Accept msg from SendMsgTool successfully!\n");
    
            memset(szBuffer, 0x00, sizeof(szBuffer));
            iLenth = recv(clientSocketfd, szBuffer, BUFFER_LEN-1, 0);
            if (iLenth <= 0)
            {
                printf("Server receive data failed! strerror=%s.\n", strerror(errno));
    
                continue; 
            }
    
            printf("Receive data: %s\n", szBuffer);
            if (0 == strncmp(szBuffer, "start test.\r\n", strlen("start test.\r\n")))
            {
                g_iStart = 1;
    
                // 执行相关操作, 打印消息
                UINT8 szCmd[1024] = {0};
                sprintf(szCmd, "This is a test for SOCKET!\n");
    
                printf("The command is: %s\n", szCmd);
    
                g_iFinish = 1;       // 将结束标识置为1
            }
    
            while (1)
            {
                if (1 == g_iFinish)
                {
                    memset(szBuffer, 0x00, sizeof(szBuffer));
                    sprintf(szBuffer, "task completed\r\n");
                    if (send(clientSocketfd, szBuffer, strlen(szBuffer), 0) < 0)         // 发送结束本轮会话的消息
                    {
                        printf("Send close msg failed!\n");
                    }
                    else
                    {
                        printf("Send close msg OK!\n");
                    }
                    printf("------------------------------------------\n");
    
                    g_iFinish = 0;
                    g_iStart = 0;
                    break;
                }
            }
        }
    
        return 0;
    }
    

    程序详解
    通过以上代码,我们可以看到,socket的整个消息流程为:
    第一步,创建socket。
    第二步,绑定指定的IP地址和端口。如果绑定失败,则跳到第一步。
    第三步,启动监听。如果没有监听到消息,则程序一直处于监听状态;如果监听到了消息,则执行下一步。
    第四步,循环从监听队列中获取消息,并根据消息内容执行相关的操作。
    第五步,操作执行完毕,向发送消息的模块返回相关消息。

    在整个过程中,涉及到了多个socket函数,包括:close、socket、inet_addr、setsockopt、bind、listen、accept、recv、send等,对这些函数的详细介绍请上网查询。

    makefile文件内容
    本程序在Linux下编译运行,makefile文件的内容为:

    TestSocket : TestSocket.c
        gcc -c -g TestSocket.c
        gcc -g -o release/TestSocket TestSocket.o
        rm *.o

    程序运行结果
    通过一自研的消息发送工具连续向该程序发送三次消息,结果如下:

    zhou@Linux:~/zhouzhaoxiong/TestSocket/release> TestSocket
    Succeeded to bind ipaddr:10.116.32.139, port:8999!
    ------------------------------------------
    Accept msg from SendMsgTool successfully!
    Receive data: start test.
    
    The command is: This is a test for SOCKET!
    
    Send close msg OK!
    ------------------------------------------
    ------------------------------------------
    Accept msg from SendMsgTool successfully!
    Receive data: start test.
    
    The command is: This is a test for SOCKET!
    
    Send close msg OK!
    ------------------------------------------
    ------------------------------------------
    Accept msg from SendMsgTool successfully!
    Receive data: start test.
    
    The command is: This is a test for SOCKET!
    
    Send close msg OK!
    ------------------------------------------

    可以看到,程序成功绑定IP地址和端口之后,就一直处于监听状态。只要有消息发过来,它就会执行后续的消息处理。

    总结
    socket有着非常悠久的历史,同时在实际的软件开发项目中也有着很广泛的应用。作为合格的软件开发工程师,大家一定要掌握其使用方法。


    本人微信公众号:zhouzxi,请扫描以下二维码:
    这里写图片描述



沪ICP备19023445号-2号
友情链接