#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define BACKLOG 10
#define cmd_length 20
//=============服务器端命令集=============
int cmd_gettime(int fd)
{
system(“date”);
//如何将服务端的命令输出,向客户端输出
return 1;
}
int cmd_netstart(int fd)
{
system(“/etc/netstart “);
send(fd, “system service has reloaded !\n”, 26, 0);
return 1;
}
int cmd_help(int fd)
{
int i;
char cmd[4][50];
strcpy(cmd[0],”getdate ->取服务器时间”);
strcpy(cmd[1],”netstart ->重启系统服务”);
strcpy(cmd[2],”help ->系统帮助” );
strcpy(cmd[3],”discon ->退出连接” );
for (i=0; i<4; i++)
send(fd, cmd[i], 50, 0);
return 1;
}
int cmd_disconnect(int fd)
{
close(fd);
waitpid(-1, NULL, WNOHANG);
exit(0);
}
/*=============服务程序=============
根据客户端传送的指令,执行相应程序*/
int run_service(int fd)
{
char cmd[cmd_length+1]={0};
int i;
for (;;)
{
if (recv(fd, cmd, cmd_length, 0)== -1)
{
cmd[0]=’\0′;
continue;
}
else
{
i= 0;
while (cmd[i]!=’\0′)
{
cmd[i]=toupper(cmd[i]);
i++;
}
switch(cmd)
{
case ‘GETTIME’ : cmd_gettime(fd);
case ‘NETSTART’: cmd_netstart(fd);
case ‘HELP’ : cmd_help(fd);
case ‘DISCONN’ : cmd_disconnect(fd);
}
if (send(fd, cmd, cmd_length, 0)== -1)
perror(“send error! \n”);
}
}
}
int main(int argc, char *argv[])
{
int SERVPORT;
int sockfd, client_fd;
int sin_size;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
if (argc >1)
{
if ((SERVPORT=atoi(argv[1]))<0) SERVPORT= 3333;
}
else
SERVPORT= 3333;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror(“socket create error ! \n”);
exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror(“bind error ! \n”);
exit(1);
}
if (listen(sockfd, BACKLOG) == -1)
{
perror(“listen error ! \n”);
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size))==-1)
{
perror(“accept error! \n”);
continue;
}
printf(“received a connection from %s \n”, inet_ntoa(remote_addr.sin_addr));
if (!fork())
{
run_service(client_fd);
}
close(client_fd);
}
}
>> 本文固定链接: http://www.vcgood.com/archives/1720
switch(cmd)
{
case ‘GETTIME’ : cmd_gettime(fd);
case ‘NETSTART’: cmd_netstart(fd);
case ‘HELP’ : cmd_help(fd);
case ‘DISCONN’ : cmd_disconnect(fd);
}
这段有问题。
少了break,并且switch里面好像只能有整数类型和字符类型。
再请教:如何将服务端的命令输出,向客户端输出
/*=============服务程序=============
根据客户端传送的指令,执行相应程序*/
int run_service(int fd)
{
char cmd[cmd_length+1]={0};
int i;
int opt=-1;
for (;;)
{
if (recv(fd, cmd, cmd_length, 0)== -1)
{
cmd[0]=’\0′;
continue;
}
else
{
i= 0;
while (cmd[i]!=’\0′)
{
cmd[i]=toupper(cmd[i]);
i++;
}
if(strcmp(cmd,”GETTIME”) == 0)
opt=0;
else if(strcmp(cmd,”NETSTART”) == 0)
opt=1;
else if(strcmp(cmd,”HELP”) == 0)
opt=2;
else if(strcmp(cmd,”DISCONN”) == 0)
opt=3;
switch(opt)
{
case 0 : cmd_gettime(fd);break;
case 1 : cmd_netstart(fd);break;
case 2 : cmd_help(fd);break;
case 3 : cmd_disconnect(fd);break;
}
if (send(fd, cmd, cmd_length, 0)== -1)
perror(“send error! \n”);
}
}
}
使用管道来获取命令行输出!
另外,Socket编程时最要使用select来读写数据。
下面修改后的代码,父进程退出部分没有写!还有一些信号处理也没写!另外发送数据的时候应该检测sockfd是否可写,这个也需要用select来实现。
[code]
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <errno.h>
#define BACKLOG 10
#define CMDLEN 256
#define BUFSIZE (16*1024)
#define SVRPORT 3333
#define CMDSIZE 4
int running = 1;
int errno;
typedef struct tagCMD {
char cmd[ CMDLEN ];
int (*execmd)( int fd );
} CMD;
int cmd_gettime( int fd );
int cmd_netstart( int fd );
int cmd_help( int fd );
int cmd_exit( int fd );
//=============服务器端命令集=============
CMD SYSCMD[ CMDSIZE ] = {
{ "gettime", cmd_gettime },
{ "netstart", cmd_netstart },
{ "help", cmd_help },
{ "exit", cmd_exit }
};
void execcmd( char *cmd, int fd )
{
int cnt;
for( cnt = 0; cnt < CMDSIZE; cnt++ ) {
if( strcmp( cmd, SYSCMD[ cnt ].cmd ) == 0 ) {
SYSCMD[ cnt ].execmd( fd );
break;
}
}
}
int cmd_gettime( int fd )
{
FILE *fp;
char line[ BUFSIZE ];
char *pch;
fp = popen( "date", "r" );
if( (FILE *)0 == fp ) return -1;
pch = fgets( line, sizeof( line ), fp );
if( pch != (char *)0 ) {
printf( "%s[%d]: %s\n", __FILE__, __LINE__, line );
send( fd, line, strlen( line ), 0 );
} else {
printf( "%s[%d]: Error\n", __FILE__, __LINE__ );
send( fd, "error", strlen( "error" ), 0 );
}
pclose( fp );
return 0;
}
int cmd_netstart( int fd )
{
system( "/etc/netstart" );
send( fd, "system service has reloaded!\n", strlen( "system service has reloaded!\n" ), 0 );
return 0;
}
int cmd_help( int fd )
{
int i;
char cmd[4][50];
strcpy( cmd[0], "gettime ->取服务器时间" );
strcpy( cmd[1], "netstart ->重启系统服务" );
strcpy( cmd[2], "help ->系统帮助" );
strcpy( cmd[3], "exit ->退出连接" );
for( i=0; i<4; i++ ) {
send( fd, cmd[i], strlen( cmd[ i ] ), 0 );
}
return 0;
}
int cmd_exit( int fd )
{
running = 0;
send( fd, "exit\n", strlen( "exit\n" ), 0 );
return 0;
}
/*=============服务程序=============*/
int run_service( int fd )
{
char cmd[ BUFSIZE ]={0};
int ret;
fd_set fd_recv;
int recvsize = 0;
struct timeval tm = { 0 };
tm.tv_sec = 3600 * 24;
while( running ) {
FD_ZERO( &fd_recv );
FD_SET( fd, &fd_recv );
ret = select( fd + 1, &fd_recv, NULL, NULL, &tm );
if ( ( ret == -1 ) && ( errno == EINTR ) ) { /* interrupted by signal */
continue;
} else if ( ret == -1 ) { /* real select error */
break;
} else if ( ret == 0 ) { /* timeout */
continue;
}
if( FD_ISSET( fd, &fd_recv ) ) {
if( ( recvsize = recv( fd, cmd, BUFSIZE, 0 ) ) <= 0 ){
break;
}
execcmd( cmd, fd );
}
}
}
int main( int argc, char *argv[] )
{
int svr_port;
int listen_fd;
int sock_fd;
int addrlen;
int ret;
struct sockaddr_in listen_addr;
struct sockaddr_in remote_addr;
svr_port = SVRPORT;
if ( (argc != 2) && (argc != 1) ) {
perror( "error\n" );
return 0;
}
if ( argc = 2 ) {
if( atoi( argv[ 1 ] ) > 0 ) svr_port = atoi( argv[ 1 ] );
}
if ( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1) {
perror("Socket Create Error!\n");
exit( -1 );
}
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons( svr_port );
listen_addr.sin_addr.s_addr = htonl( INADDR_ANY );
bzero( &(listen_addr.sin_zero), 8 );
if ( bind( listen_fd, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr) ) == -1 ) {
perror("bind error ! \n");
close( listen_fd );
exit( -1 );
}
if ( listen( listen_fd, BACKLOG ) == -1 ) {
perror("listen error ! \n");
close( listen_fd );
exit( -1 );
}
while( running ) {
addrlen = sizeof( struct sockaddr_in );
if ( ( sock_fd = accept( listen_fd, (struct sockaddr*)&remote_addr, &addrlen ) ) == -1 ) {
perror("accept error! \n");
continue;
}
printf("Client: %s\n", inet_ntoa(remote_addr.sin_addr));
ret = fork();
if ( ret == -1 ) {
perror( "fork() error\n" );
close( listen_fd );
close( sock_fd );
exit( -1 );
} else if( ret == 0 ) {
close( listen_fd );
run_service( sock_fd );
close( sock_fd );
exit( 0 );
}
close( sock_fd );
waitpid( ret, NULL, 0);
}
close( listen_fd );
return 0;
}
[/code]
感谢大虾的修改,程序中有几处还望指教:
1、typedef struct tagCMD {
char cmd[ CMDLEN ];
int (*execmd)( int fd );
} CMD;
int (*execmd)(int fd),中*execmd是什么,整句如何理解
2、printf( “%s[%d]: %s\n”, __FILE__, __LINE__, line );
__FILE__, __LINE__意义是什么,man中没有找到解释
3、fd_set fd_recv;
fd_set 类型在man没有解释
1、int (*execmd)(int fd);
execmd是个函数指针,指向的函数的返回类型是int型的,并带一个int型参数。
通过赋值可以调用任何同类型的函数。比如cmd_exit等。
2、__FILE__和__LINE__是编译器定义的宏,表示当前文件名和当前行,这个在调试代码的时候可以方便定位代码行。
3、fd_set在不同系统里的实现似乎不一样的,有些将其实现为一个数组,有些将其按位实现。
你可以查看一下FD_ISSET等宏定义。这些在man中是有的。
select函数检查的是文件描述符是否可读写,可读写则置相应的位。