作者:fbysss
msn:jameslastchina@hotmail.com
blog:blog.csdn.net/fbysss
声明:本文由fbysss原创,转载请注明出处
关键字: 实用工具源码  Windows下查看Linux编译信息
一、背景:本人写C程序不多,更不用说Linux下了。偶然一个机会,接了个这样的活,vi我用的还马马虎虎,但程序超过一千行,看起来就有些眼花了。于是只好在VC下编写代码,ftp传到Linux服务器,再用gcc编译,出错了再到VC下修改,再上传,如此这般,颇为费劲。Linux图形界面下安装一个C的开发工具?还是算了,我的Linux是虚拟机,在本机上使用Shell我都用的SecureCRT,就是不想切换来切换去。那有什么方式能更自动化一点呢?似乎没有比较贴心的方案,犹豫再三,花了一个下午写了这个工具,完全满足了自己的要求。在此分享给大家,希望对读者有所帮助。
二、设计思路:在Linux下运行一个守护进程,Windows下提供一个客户端供IDE调用,传递gcc命令行、文件名、文件内容(最开始考虑用ftp,后来一不做二不休,想让一切更简单些,索性把文件内容也通过Socket传过去了。)
三、源代码:
1.Linux下守护程序compileDaemon.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netdb.h>
#include <pthread.h>
#include <sys/stat.h>
/*******************************************************
文件名:compileDaemon.c
功能:Windows下查看Linux下编译信息--Linux下编译守护程序
编写人:fbysss
blog:blog.csdn.net/fbysss
email:jameslastchina@hotmail.com
********************************************************/
#define SPLIT  "###SPLIT###"
#define BUFLEN 1024*128
#define THREAD_NUM 1
pthread_mutex_t sock_mutex;
pthread_cond_t sock_cond;
#define MAXSIZE 512
#define resultFile "compile.log"
/**
所需参数:shellCommand,由client传递
包括gcc +参数  里面包含c源程序和目标文件名
*/
/********处理每个连接*******/
void * dealEachConn(void * arg)
{ char buf[MAXSIZE];
 char recvBuf[BUFLEN];
 //int filesize;//实际上没有使用。
 FILE * fdSrcFile;
 char cmdLine[MAXSIZE]={0};
 int len;
 
 char * recvBufHead;
 char * recvBufP;
 char  filepath[256];
 char compileStr[1024]={0}; 
 struct stat file_stat;
 int each_conn_fd=(int) arg; 
 len = recv(each_conn_fd, recvBuf, BUFLEN, 0);
 if (len < 0)
 {
  perror("nothing recieved.");
  return;
 }
 recvBufHead = recvBuf;
 recvBufP = recvBuf; 
 sprintf(cmdLine,"%s",recvBufP);
 recvBufP+=strlen(cmdLine);
 recvBufP++;//字符串结束符
 recvBufP+=strlen(SPLIT);
 //得到文件名
 sprintf(filepath,"%s",recvBufP);
 printf("filepath :%s/n",filepath);
 recvBufP+=strlen(filepath);
 recvBufP++;//字符串结束符
 recvBufP+=strlen(SPLIT); 
 
 //写文件
 fdSrcFile = fopen(filepath,"w");
 fwrite(recvBufP,len-(recvBufP-recvBufHead)-1,1,fdSrcFile);
 fclose(fdSrcFile);
 printf("file total %d bytes writed,/n",len-(recvBufP-recvBufHead));
 //组装命令行
 strcat(cmdLine," 2>&1|tee ");
 strcat(cmdLine,resultFile);
 printf("commandLine is:%s/n",cmdLine);
 system(cmdLine);
 FILE * fd = fopen(resultFile,"r");
 while(fgets(buf, MAXSIZE, fd)!=NULL)
 {
  strcat(compileStr,buf);
 }
 printf("compileStr is:%s/n",compileStr);
 int rtValue = send(each_conn_fd, compileStr, strlen(compileStr), 0);
 fclose(fd);
 close(each_conn_fd);
}
//启动一个线程
void startThreadPro(void * proc,void *arg)
{
 /* initialize */
    pthread_t* arr_pid = (pthread_t*)malloc(sizeof(pthread_t) * THREAD_NUM);
    pthread_mutex_init(&sock_mutex, NULL);
    pthread_cond_init(&sock_cond, NULL);
 printf("create thread a proc .../n");
 pthread_create(&arr_pid, NULL, proc, arg);
}
/**************************主程序*******************************/
int main(int argc, char **argv)
{
    int each_conn_fd;
 int sockfd;
    socklen_t len;
    struct sockaddr_in my_addr, their_addr;
    unsigned int myport, lisnum;
 /*****************************************初始化*****************************************/

    if (argv[1])
        myport = atoi(argv[1]);
    else
        myport = 4444;
    if (argv[2])
        lisnum = atoi(argv[2]);
    else
        lisnum = 2;
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(myport);
    if (argv[3])//第三个参数为ip地址,指定绑定到哪个ip地址上。
        my_addr.sin_addr.s_addr = inet_addr(argv[3]);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;
/*******************************端口绑定bind**************************************************/
    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
        == -1) {
        perror("bind");
        exit(1);
    }
/***********************************侦听*****************************************************/
    if (listen(sockfd, lisnum) == -1) {
        perror("listen");
        exit(1);
    }
    while (1) {//while 1   //循环侦测客户端连接         
        len = sizeof(struct sockaddr);
        if ((each_conn_fd =
             accept(sockfd, (struct sockaddr *) &their_addr,//通过accept能够取得跟服务器连接的客户机地址their_addr,返回new_fd
                    &len)) == -1) {
   if (errno == EINTR){//避免信号对accept的影响
    continue;
   }
            perror("accept");
            exit(errno);
        } else
  {
            printf("server: got connection from ip:%s, port: %d, socketfd: %d/n",
                   inet_ntoa(their_addr.sin_addr),
                   ntohs(their_addr.sin_port), each_conn_fd);
   
  }
  /* 开始处理每个新连接上的数据收发 */
 startThreadPro(dealEachConn,(void*)each_conn_fd);
    }//end while
 printf("start to close main socket.../n");
    close(sockfd);
    return 0;
}
2.Windows下客户端程序compileClient.c
#include "winsock.h"
#include "stdio.h"
/*******************************************************
文件名:compileClient.c
功能:Windows下查看Linux下编译信息--Windows 客户端
编写人:fbysss
blog:blog.csdn.net/fbysss
email:jameslastchina@hotmail.com
********************************************************/
#define BUFLEN 1024*128//这里一定要足够大。考虑到能够传送一般的c文件
#define LENGTH128 128
#define SPLIT  "###SPLIT###"
#define resultFile "compile.log"
void SocketError(char * call)
{
    fprintf(stderr," WinSock Error# function: %s, error code:%ld/n",call,WSAGetLastError());
}
/**
argv[1]:server ip
argv[2]:server port
argv[3]:send command
argv[4]:send file dir
argv[5]:send filename
*/
main(int argc,char ** argv)
{
    int index;
 int iRes,iPort,iTmp;
 char * rt;
    SOCKET sockfd;
    SOCKADDR_IN sin;
    WSADATA wsad;
    WORD wVersionReq;
 FILE * fp;
 FILE * fdSrcFile ;
 int sendLen;
    char sendBuf[BUFLEN]={0};
    char recvBuf[BUFLEN]={0};
 char * sdBufHead = sendBuf;
 char * sdBufferP = sendBuf;
 char filename[LENGTH128];
 char buf[LENGTH128]={0};
  if(argc<5)
  {
   fprintf(stderr,"Usage:winLinuxGcc <host> <port> <commandStr> <dir> <filename>/n");
   return -1;
  }
  if(inet_addr(argv[1])==INADDR_NONE)
  {
   fprintf(stderr,"Wrong ip :/n");
   return -1;
  }
  iPort=0;
  iPort=atoi(argv[2]);
  sin.sin_addr.s_addr=inet_addr(argv[1]);
  sin.sin_family=PF_INET;
  sin.sin_port=htons(iPort);
  if(iPort<=0)
  {
   fprintf(stderr,"must specify a number for port/n");
   return -1;
  }
  wVersionReq=MAKEWORD(1,1);
  iRes=WSAStartup(wVersionReq,&wsad);
  if(iRes!=0)
  {
   SocketError("WSAStartup()");
   return -1;
  }
   sockfd=socket(PF_INET,SOCK_STREAM,0);
  if(sockfd==INVALID_SOCKET)
  {
   SocketError("socket()");
   return -1;
  }
  iTmp=sizeof(sin);
  fprintf(stderr,"WinSock Client Start....../n");
  if(connect(sockfd,(LPSOCKADDR)&sin,iTmp)==SOCKET_ERROR)
  {
   SocketError("connect()");
   closesocket(sockfd);
   WSACleanup();
   return -1;
  }
  //printf("debug1/n");
  strcpy(sdBufferP,argv[3]);//命令行
  //写分隔符
  sdBufferP+=strlen(argv[3]); 
  sdBufferP++;//字符串结束符
  memcpy(sdBufferP,SPLIT,strlen(SPLIT));
  sdBufferP+=strlen(SPLIT);
  //写文件名
  memcpy(sdBufferP,argv[5],strlen(argv[5]));
  sdBufferP+=strlen(argv[5]);
  //写分隔符
  sdBufferP++;  
  memcpy(sdBufferP,SPLIT,strlen(SPLIT));
  sdBufferP+=strlen(SPLIT);
  //写文件内容
  strcpy(filename,argv[4]);
  strcat(filename,"//");
  strcat(filename,argv[5]);
  printf("debug:filename is:%s/n",filename);
  fdSrcFile = fopen(filename,"r");
  if(fdSrcFile<0)
  {
   perror("open file error:");
  }
  rt="1";
  index = 0;
  while(rt!=NULL)
  //while(rt!=NULL)
  { memset(buf,0,LENGTH128);
   index ++;
   rt=fgets(buf, LENGTH128, fdSrcFile);   
   memcpy(sdBufferP,buf,strlen(buf));    
   sdBufferP+=strlen(buf);
   
  }

  sendLen = sdBufferP - sdBufHead;//计算发包长度
  iRes=send(sockfd,sendBuf,sendLen,0);
  if(iRes==SOCKET_ERROR)
  {
   SocketError("send()");
   closesocket(sockfd);
   WSACleanup();
   return -1;
  }

  fp =fopen(resultFile,"a+b");
  if(fp==NULL)
   return -1;
  //读取返回的编译信息
  iRes=recv(sockfd,recvBuf,BUFLEN,0);
  while(iRes!=SOCKET_ERROR&&iRes!=0)
  {
   printf("Received %d bytes,Data:/n------------------/n%s/n------------------/n",iRes,recvBuf);
   fwrite(recvBuf,sizeof(char),iRes,fp);//写日志文件
   iRes=recv(sockfd,recvBuf,BUFLEN,0);
  }
  fclose(fp);
  closesocket(sockfd);
  WSACleanup();
  return 0;
}

四.编译运行守护程序

  • 上传compileDaemon到Linux;
  • 在Linux shell下,运行gcc -o compileDaemon compileDaemon.c编译程序;
  • 再输入./compileDaemon 4444 1,运行成功,进入守护监听状态。


五.客户端与VC集成配置

  • 首先建立一个工程,winLinuxGcc,加入文件compileClient.c,build之后,生成winLinuxGcc.exe。
  • tools->customize..-tools ,添加Menu Contents,输入 LinuxGCC,command输入winLinuxGcc.exeArguments输入<host> <port> "gcc -o ttt $(FileName)$(FileExt)" $(FileDir) $(FileName)$(FileExt)  注意:<host> <port>请根据实际情况进行修改),并选中Use Output Window

    • 任意打开一个需要在Linux下编译的程序,点击菜单tools,可以看到增加了一个菜单项“LinuxGcc”,点击该菜单,即可可以看到IDE下方输出窗口中的编译信息。

 

六、结束语:

  • 本程序是针对GCC编写的, 客户端的第三个参数可以根据实际情况进行灵活配置。可以完全把Linux命令行格式放置到客户端,这样,不仅仅是gcc,其他编译器也可以适用(服务端稍作改动即可)。
  • 另外,除了VC,Editplus、UtraEdit以及其他可加入扩展命令的IDE同样适用本工具。进一步,不仅仅是C语言,其他语言,同样可以采用本工具来达到类似效果。
  • 局限性:本工具的编写主要是出于“背景”所述原因,满足的需求有限,并不能完成真正意义的交互调试,我不过是抛砖引玉,希望这样的尝试,能给大家带来更多启示,如果有人能把gdb的交互调试也在vc下实现了,那必定很酷。

 

Logo

更多推荐