技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 网络系统 --> socket消息流程介绍及其C代码实现

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

浏览:2347次  出处信息

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

   C程序示例

   /**********************************************************************

   * 版权所有 (C)2015, Zhou Zhaoxiong。

   *

   * 文件名称:TestSocket.c

   * 文件标识:无

   * 内容摘要:测试socket从创建到结束的整个过程

   * 其它说明:无

   * 当前版本: V1.0

   * 作       者: Zhou Zhaoxiong

   * 完成日期: 20150319

   *

   **********************************************************************/

   #include <stdio.h>

   #include <stdlib.h>

   #include <string.h>

   #include <errno.h>

   #include <netinet/in.h>

   #include <sys/socket.h>

   // 宏定义

   #define INVALID_SOCKET -1

   #define SOCKET_ERROR   -1

   #define BUFFER_LEN     1024

   #define SERVERPORT     8999

   #define IPADDR         "10.116.32.139"

   // 重定义数据类型

   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;

   /**********************************************************************

   * 功能描述:主函数

   * 输入参数:无

   * 输出参数:无

   * 返  回 值:无

   * 其它说明:无

   * 修改日期        版本号     修改人            修改内容

   * -------------------------------------------------------------------

   * 20150319       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有着非常悠久的历史,同时在实际的软件开发项目中也有着很广泛的应用。作为合格的软件开发工程师,大家一定要掌握其使用方法。

建议继续学习:

  1. 推荐一些socket工具,TCP、UDP调试、抓包工具    (阅读:9480)
  2. 推荐一些socket工具,TCP、UDP调试、抓包工具    (阅读:7335)
  3. 用unix socket加速php-fpm、mysql、redis的连接    (阅读:6602)
  4. 浅析linux kernel network之socket创建    (阅读:5766)
  5. nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket    (阅读:5054)
  6. web socket 心跳包的实现方案    (阅读:4979)
  7. python中的socket代理    (阅读:4867)
  8. netstat和web主机socket文件分析    (阅读:4491)
  9. 使用socket.io和node.js搭建websocket应用    (阅读:4404)
  10. php socket为什么这么慢,直到超时    (阅读:3964)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1