/*******************************************************
File name: server.c
Description:
功能为连接客户端,接收客户端传入命令,通过
popen执行shell命令并将结果发送回客户端.
端口号:8000
ip地址:127.0.0.1
Function List:
int my_popen(int cfd); //popen执行函数,接收传入的命令,
//执行sh并将结果发送到客户端
void *tfn(void *); //线程的执行函数
ssize_t sendn_t(int fd, void *vptr,size_t n);
ssize_t recvn_t(int fd,void *vptr, //
size_t n, int flags);
******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERV_PORT 8000 //端口号
#define MAX_LIS 1024 //listen最大等待数
#define MAXLINE 1024*10 //数组的最大值
#define MAX_ACCE 1 //服务器可连接客户端上限MAX_ACCE+1
#define TIME_OUT_TIME 20 //recv超时时间
int accp_count = 0; //服务器连接计数器
int my_popen(int cfd);
ssize_t sendn_t(int fd, void *vptr,size_t n);
ssize_t recvn_t(int fd,void *vptr, size_t n);
void *tfn(void *); //pthread_creat执行函数
typedef struct msg_fd{ //传递描述符的结构
int lfd;
int cfd;
} msg_fd_t;
typedef struct msg_header{ //recv 和send 的报头
int body_len;
}msg_header_t;
int main( int argc, char **argv )
{
int lfd = -1; //监听
int cfd = -1; //连接
pthread_t tid;
socklen_t addrlen,len;
msg_fd_t *connfd;
struct sockaddr_in servaddr;
struct sockaddr *cliaddr;
struct timeval tv;
signal(SIGHUP,SIG_IGN);
if( ( lfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1)
{
perror("socket");
exit(1);
}
printf("lfd = %d\n", lfd);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
int i = 1;
setsockopt( lfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i) );
if(bind( lfd, (struct sockaddr *)&servaddr,
sizeof(servaddr)) == -1 )
{
perror("bind");
close(lfd);
exit(1);
}
printf("Bind success!\n");
if( listen( lfd, MAX_LIS ) == -1)
{
perror("listen");
close(lfd);
exit(1);
}
printf("Listening....\n");
cliaddr = malloc(addrlen); //为cliaddr注册空间
if( cliaddr == NULL )
{
printf("malloc errer\n");
close(lfd);
return 0;
}
while(1)
{
len = addrlen;
/*为连接套接字分配空间*/
if( (cfd = accept( lfd, cliaddr, &len)) < 0 )
{
perror("accept error");
goto l2;
} else {
/*如果达到连接上限,将连接描述符关闭计数器不计数*/
if( accp_count > MAX_ACCE )
{
close(cfd);
printf("socket %d close\n",(cfd));
continue;
}
/*如果accept成功,计数器累加*/
connfd = malloc(sizeof(msg_fd_t));
if( connfd == NULL )
{
printf("malloc connfd error!\n");
l3:
close(cfd);
l2:
free(cliaddr);
close(lfd);
return 0;
}
connfd->cfd = cfd;
perror("accept");
accp_count++;
/*打印连接描述符号*/
printf("accept no =%d\n",(connfd->cfd));
}
/*创建线程*/
if( pthread_create( &tid, NULL, &tfn, connfd ) != 0 )
{
printf("pthread__%d__in\n",accp_count);
perror("pthread_create");
accp_count--;
free(connfd);
close(cfd);
}
// return 0;
}
/*while(1) end*/
return 0;
}
/*线程执行函数*/
void *tfn( void *arg )
{
msg_fd_t *connfd;
connfd = (msg_fd_t *)arg;
/*当线程退出后,连接计数器减一,并关闭连接套接字*/
if( pthread_detach(pthread_self() ) == 0 )
{
perror("pthread_detach");
} else {
printf("errno %d error %s \n",errno,strerror(errno));
perror("fail to detach");
goto done;
}
my_popen( (connfd->cfd) );
done:
printf("pthread__%d__out\n",(accp_count-1));
accp_count--;
printf(".....*tfn cfd %d\n",connfd->cfd);
close(connfd->cfd);
free(connfd);
return (NULL);
}
/*执行popen函数*/
int my_popen( int cfd )
{
ssize_t n = 0;
ssize_t headern = 0; //报头的长度
int result = 0; //用于设置recv超时
int count = 0;
int nread = 0; //读取popen结果
int nbytes = 0;
char *p = NULL;
char *q = NULL;
char recv_buf[MAXLINE];
char send_buf[MAXLINE];
char buf[MAXLINE];
FILE *fp;
msg_header_t header; //send and recv 报头
msg_fd_t *connfd; //传入套接字结构
struct timeval tv; //设置超时时间
signal(SIGHUP,SIG_IGN);
/*设置recv超时*/
tv.tv_sec = TIME_OUT_TIME;
tv.tv_usec= 0;
result = setsockopt( cfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );
if( result < 0 )
{
perror("popen setsockopt");
close(cfd);
return -1;
}
while(1)
{
memset( recv_buf, 0, sizeof(recv_buf) );
memset( &header, 0, sizeof(msg_header_t) );
/*判断recv超时处理*/
headern = recvn_t( cfd, &header, sizeof(msg_header_t));
if( headern < 0 )
{
if( errno == EWOULDBLOCK )
{
fprintf(stderr,"socket timeout \n");
/**/
perror("client exit");
return -1;
}
if(errno == EINTR)
{
printf("errno %d, error %s \n", errno, strerror(errno));
continue;
}
}
printf("header%d \n",header.body_len);
if( ( n =recvn_t(cfd, recv_buf, header.body_len) ) < 0)
{
perror("recv data error");
return -1;
}
if( n == 0)
{
perror("recv none");
break;
}
printf("1:%s\n",recv_buf); //打印接收到的内容
if( ( fp = popen(recv_buf, "r") ) == NULL )
{
perror("popen error");
return -1;
}
// printf("2%s\n",recv_buf);
/*为send内容分配内存空间*/
count = (sizeof(char) * MAXLINE);
p = (char *)malloc(count);
if( p == NULL )
{
printf("malloc in popen p error!\n");
goto error;
}
nread = 0;
while( !feof(fp) )
{
if( nread + 32 > count )
{
if( (q = (char *)malloc(sizeof(char) * MAXLINE)) != NULL )
{
memcpy(q, p, count);
free(p);
p = q;
} else {
printf("errno %d error %s \n",errno,strerror(errno));
goto error1;
}
}
nread += fread( p+nread, 1, count-nread, fp );
}
/*send data*/
memset( &header, 0, sizeof(msg_header_t) );
header.body_len = nread;
if( sendn_t( cfd, &header, sizeof(msg_header_t) ) < 0 )
{
perror("send header error");
goto error1;
}
if ( sendn_t(cfd, p, header.body_len) < 0 )
{
perror("send data error");
goto error1;
error1:
free(p);
error:
pclose(fp);
return -1;
}
printf("headlen%d\n", header.body_len); //打印发送内容长度
//printf("%s",p); //打印p空间内发送的内容
free(p);
pclose(fp);
pri