socket消息流程介绍及其C代码实现
在实际的软件开发工作中,经常会涉及到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有着非常悠久的历史,同时在实际的软件开发项目中也有着很广泛的应用。作为合格的软件开发工程师,大家一定要掌握其使用方法。
建议继续学习:
- 推荐一些socket工具,TCP、UDP调试、抓包工具 (阅读:9428)
- 推荐一些socket工具,TCP、UDP调试、抓包工具 (阅读:7266)
- 用unix socket加速php-fpm、mysql、redis的连接 (阅读:6503)
- 浅析linux kernel network之socket创建 (阅读:5706)
- nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket (阅读:5005)
- web socket 心跳包的实现方案 (阅读:4927)
- python中的socket代理 (阅读:4813)
- netstat和web主机socket文件分析 (阅读:4436)
- 使用socket.io和node.js搭建websocket应用 (阅读:4368)
- php socket为什么这么慢,直到超时 (阅读:3868)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:周兆熊 来源: 周兆熊的博客
- 标签: socket
- 发布时间:2015-03-26 13:50:18
- [55] Oracle MTS模式下 进程地址与会话信
- [55] IOS安全–浅谈关于IOS加固的几种方法
- [54] 如何拿下简短的域名
- [53] 图书馆的世界纪录
- [53] android 开发入门
- [52] Go Reflect 性能
- [49] 读书笔记-壹百度:百度十年千倍的29条法则
- [49] 【社会化设计】自我(self)部分――欢迎区
- [38] 程序员技术练级攻略
- [33] 视觉调整-设计师 vs. 逻辑