openwrt 使用 pthread 实现 socket 多进程服务端

千呼万唤始出来,我终于在电脑里面找到一个去年的 openwrt 的socket多进程服务端代码,虽然是初期的代码,当时麻雀虽小,五脏俱全啊,功能大致还有,想想当时学习 c 语言写代码的时候真是感慨啊,可是写了那么多代码,没从公司复制过来,有点失策。

下面简单介绍下这个 openwrt 上的 socket 多进程服务端吧。

看看代码

这个是 c 语言代码,当时写的代码不怎么样,勿喷啊。需要说明的是,这里用到了 Linux 的一些库,直接在 Windows 上面是无法编译的,可以在 Windows上的子系统编译,有需要可以看我之前博客。

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <signal.h>
#include <pthread.h>
 
#define IP	"192.168.121.1"
#define PORT  2050
#define QUEUE   10
#define BUFFER_SIZE 8196

//接收数据
void *recv_data(int conn_fd);

//获取字符串形式文件参数
char* get_args();
 
int main()
{
	
	printf("This is 17:31");
		
	//手动捕获管道破裂信号,并忽略
	signal(SIGPIPE, SIG_IGN);
	
    ///定义sockfd
    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
	int conn;
 
    ///定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;//IPv4
    server_sockaddr.sin_port = htons(PORT);
    server_sockaddr.sin_addr.s_addr = inet_addr(IP);//需要置顶IP,不然连不上
	bzero(&(server_sockaddr.sin_zero),8);//填充结构体剩余部分
 
    ///bind,成功返回0,出错返回-1
    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    {
        perror("bind");
        exit(1);
    }
	
	printf("bind success, start listen!");
 
    ///listen,成功返回0,出错返回-1
    if(listen(server_sockfd,QUEUE) == -1)
    {
        perror("listen");
        exit(1);
    }
	
	while(1)
    {
        pthread_t thread;
		
		///客户端套接字
		struct sockaddr_in client_addr;
		socklen_t length = sizeof(client_addr);
 
        if (-1 == (conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length)))
        {
            perror("accept");
            continue;
        }
 
        if (0!= pthread_create(&thread, NULL, recv_data, conn))
        {
            perror("pthread_create");
            break;
        }
    }
 
    shutdown(server_sockfd,2);
    shutdown(conn,2);
    return 0;

}


void *recv_data(int conn_fd)
{
    int  recv_len;
    char recv_buf[BUFFER_SIZE];
 
    for(;;)
    {
		bzero(recv_buf, sizeof(recv_buf));
        recv_len = recv(conn_fd,recv_buf,BUFFER_SIZE,0);
 
        if(-1==recv_len)
        {
            perror("recv");
            exit(1);
        }
        
		recv_buf[recv_len] = '\0';
 
        if(strncmp(recv_buf,"exit",4)==0)
        {
            printf("%s\n",recv_buf);
            break;
        }
		
		 
        printf("Receive data:%s\n", recv_buf);
		
		if(send(conn_fd, get_args(), strlen(get_args()), 0) == -1)
		{
			perror("send");
            exit(1);
		}
		
    }
 
    close(conn_fd);
    pthread_exit(NULL);
}

char* get_args()
{
	//char data[8196];
	//char *data = malloc(8196);
	char *data = (char*)calloc(BUFFER_SIZE, sizeof(char));//带初始化
	char tmp[8] = { 0 };
    FILE* pFile = fopen("/etc/config/site-manager", "r");
    while ( fread(tmp, sizeof(char), 2, pFile) )
    {
        strcat(data,tmp);
		bzero(tmp,sizeof(tmp));
        //memset(tmp,0,sizeof(tmp));
    }
    fclose(pFile);
	return data;
}

这里用到了 pthread 来做多线程,数据是从 /etc/config/ 拿的 uci 参数,后面有时间可以讲讲 uci 参数,这个是可以从网页上修改的,支持双向绑定。

这里使用的是 UDP的服务端,也可以写成 TCP,都差不多,可以自行研究。

    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);

其他额注释都写的很清楚,当时刚毕业态度还是很端正的,值得注意的是有个管道破裂的问题,在 socket 客户端直接挂断 socket 连接,服务端不知情,会导致服务端到客户端连着,客户端到服务端断开的情形,这时候服务端应用一旦发送数据到客户端,就会出现管道破裂的 error,导致服务端程序被关闭,反正就是让你加上下面这句话吧

	//手动捕获管道破裂信号,并忽略
	signal(SIGPIPE, SIG_IGN);

编写配置文件

因为引入了 pthread 库,我们的配置文件需要做出一定修改。

  • 源码目录 Makefile
argserver : argserver.o
	$(CC) $(LDFLAGS) argserver.o -o argserver -lpthread

argserver.o : argserver.c
	$(CC) $(CFLAGS) -c argserver.c

clean :
	rm *.o argserver

这里在编译的时候需要加上 -lpthread,表示增加该库参与编译。

  • 外层 Makefile
include $(TOPDIR)/rules.mk

PKG_NAME:=argserver
PKG_RELEASE:=1.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
TARGET_LDFLAGS:= -lpthread

include $(INCLUDE_DIR)/package.mk

define Package/argserver
	SECTION:=utils
	CATEGORY:=Utilities
	TITLE:=argserver -- socket server to get arg info
	DEPENDS:=+libpthread
endef

define Package/argserver/description
	socket server to get arg info .
endef

define Build/Prepare
	echo "Here is Package/Prepare"
	mkdir -p $(PKG_BUILD_DIR)
	$(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Package/argserver/install
	echo "Here is Package/install"
	$(INSTALL_DIR) $(1)/bin $(1)/etc/init.d/
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/argserver $(1)/bin/
	$(INSTALL_BIN) ./auto/argserver $(1)/etc/init.d/
endef

$(eval $(call BuildPackage,argserver))

注意两处修改,下面表示增加依赖库,上面那个是参与编译。

支持 pthread

一般来说,openwrt 应该默认增加了 pthread 库,如果不确定的话,可以在菜单里面找找

make menuconfig

在菜单里面使用 “/”,搜索 pthread 看看有没有被勾选上,勾选上了我们的程序就能正常运行了。如果你用的 openwrt 没法编译固件,就要看你用的固件支不支持 pthread 了,一般来说都有。

测试

网上随便找个 udp 测试工具就可以了 ,像什么 TCPUDPDbg 啊,网上下一个,用起来很简单,我就不写了。也推荐一下一个多功能工具 IPOP,用起来不错,听说是华为开发,搜一下就知道了。

结语

什么自启动功能就看我上一篇博客吧。

end
完美撒花

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值