IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

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

周兆熊的博客 2015-03-26 13:50:18 累计浏览 2,978 次
本机暂存

   在实际的软件开发工作中,经常会涉及到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. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. Linux如何统计进程的CPU利用率 (累计阅读 16,308)
  2. 我的 RHCA 之路 (累计阅读 14,013)
  3. Linux内存点滴 用户进程内存空间 (累计阅读 13,230)
  4. 给程序员新手的一些建议 (累计阅读 13,089)
  5. Linux 性能监控、测试、优化工具 (累计阅读 13,011)
  6. 关于linux内存free的一些事情 (累计阅读 12,867)
  7. ps - 按进程消耗内存多少排序 (累计阅读 12,688)
  8. Google怎么用linux (累计阅读 12,581)
  9. Linux Used内存到底哪里去了? (累计阅读 11,867)
  10. find命令的一点注意事项 (累计阅读 11,865)