logo

当前栏目:社区首页->软件开发->自由软件与linux 转到:在该栏目发表文章社区后台管理搜索
Linux程式设计- 4.socket
作者: imac 日期: 08-03-29, 02:01
UNIX Socket Programming基本上是一本书名。Socket programming其实需要相当程度的基础,我不想在这包山包海地,如果您需要彻底研究,可以买这本书来看。在此我想提供一些简单的Server/Client两端的简单写法,让你有个起点,做为进一步研究的基础。很多涉及较复杂的内容的,我在这便不详细说明,您可以照本宣科,照抄着用,稍微熟悉时,再细细研究。 

文章版权归原作者所有! (www.MegaEntry.com)

-------------------------------------------------------------------------------- Client int sock_connect(char *domain,int port)  {    int white_sock;    struct hostent * site;    struct sockaddr_in me;    site = gethostbyname(domain);    if (site==NULL) return -2;    white_sock = socket(AF_INET,SOCK_STREAM,0);    if (white_sock<0) return -1;    memset(&me,0,sizeof(struct sockaddr_in)); 

文章版权归原作者所有! (www.MegaEntry.com)

  memcpy(&me.sin_addr,site->h_addr_list[0],site->h_length);    me.sin_family = AF_INET;    me.sin_port = htons(port);    return (connect(white_sock,(struct sockaddr *)&me,sizeof(struct sockaddr))<0) ? -1 : white_sock;  }  要由Client向伺服器端要求连线的步骤,首先您必须要找出对方的位址,可利用:  gethostbyname()  接下来要建立起一个socket,然後用这个socket来建立连线。  接下来我们利用这个简单的socket程式来写一个读取WWW网页的简单浏览器(看html source)。  #include   #include  

文章版权归原作者所有! (www.MegaEntry.com)

#include   #include   #include   #include   #include   int htconnect(char *domain,int port)  {    int white_sock;    struct hostent * site;    struct sockaddr_in me;    site = gethostbyname(domain);    if (site==NULL) return -2;    

MegaEntry 网络社区与信息交流平台!

  white_sock = socket(AF_INET,SOCK_STREAM,0);    if (white_sock<0) return -1;    memset(&me,0,sizeof(struct sockaddr_in));    memcpy(&me.sin_addr,site->h_addr_list[0],site->h_length);    me.sin_family = AF_INET;    me.sin_port = htons(port);    return (connect(white_sock,(struct sockaddr *)&me,sizeof(struct sockaddr))<0) ? -1 : white_sock;  }  int htsend(int sock,char *fmt,...)  {    char BUF[1024];    va_list argptr;    va_start(argptr,fmt); 

MegaEntry 网络社区与信息交流平台!

  vsprintf(BUF,fmt,argptr);    va_end(argptr);    return send(sock,BUF,strlen(BUF),0);  }  void main(int argc,char **argv)  {    int black_sock;    char bugs_bunny[3];    if (argc<2) return;    black_sock = htconnect(argv[1],80);    if (black_sock<0) return;    htsend(black_sock, "GET / HTTP/1.0%c ",10);    htsend(black_sock, "Host: %s%c ",argv[1],10); 

文章版权归原作者所有! (www.MegaEntry.com)

  htsend(black_sock, "%c ",10);    while (read(black_sock,bugs_bunny,1)>0) { printf( "%c ",bugs_bunny[0]); }    close(black_sock);  }  编译: gcc -o ex1 client.c  执行 ./ex1 www.linux.org.tw  -------------------------------------------------------------------------------- Server Listen to a port

MegaEntry 网络社区与信息交流平台!

要建立起一个网路伺服器,第一步就是要 "倾远方 ",也就是要Listen。  以下是一般建立服务的方法:  int DaemonSocket;  struct sockaddr_in DaemonAddr;  int BindSocket(void)  {    DaemonSocket = socket(AF_INET,SOCK_STREAM,0);    if (DaemonSocket==-1) return 0;    DaemonAddr.sin_family = AF_INET;    DaemonAddr.sin_port   = htons(DAEMON_PORT);    if (bind(DaemonSocket,&DaemonAddr,sizeof(DaemonAddr))<0) {      printf( "Can not bind! ");      return 0;    }    if (listen(DaemonSocket,1024)!=0) { 

MegaEntry 网络社区与信息交流平台!

    printf( "Can not listen! ");      return 0;    }    return 1;  }  Incoming call 要查看是否有连线进来,可用以下方式:  int incoming_call(void)  {    fd_set sock;    struct timeval tv;    int t;    FD_ZERO(&sock); 

文章版权归原作者所有! (www.MegaEntry.com)

  FD_SET(DaemonSocket,&sock);    tv.tv_sec = 60; tv.tv_usec = 0;    t = select(DaemonSocket + 1,&sock,NULL,NULL,&tv);    if (t<=0||!FD_ISSET(DaemonSocket,&sock)) return 0;    printf( "incoming... ");    return 1;  }  Connect Client 当我们确认有人进来要求服务时,会需要accept connection,可用以下方式  int ConnectClient(void)  {    int socksize=sizeof(HostAddr);    unsigned char * addr; 

文章版权归原作者所有! (www.MegaEntry.com)

  ClientSocket = accept(DaemonSocket,(struct sockaddr*)&HostAddr,&socksize);    if (ClientSocket<0) return 0;    addr = (unsigned char *)&HostAddr.sin_addr.s_addr;    printf( "incoming address:%d.%d.%d.%d ",addr[0],addr[1],addr[2],addr[3]);    return 1;  }  注意到当您accept connection之後,连线已建立起,此时要用的socket是ClientSocket,而非DaemonSocket,ClientSocket才是真正用来连线用的socket。  这是个我才刚开始动手写的象棋伺服器。  #include  

MegaEntry 网络社区与信息交流平台!

#include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #define DAEMON_LOCK  "/var/chess/daemon.lock "  #define DAEMON_LOG   "/var/chess/daemon.log "  #define DAEMON_PORT 9901 

MegaEntry 网络社区与信息交流平台!

int DaemonSocket;  struct sockaddr_in DaemonAddr;  int ClientSocket=0;  struct sockaddr_in HostAddr;  void dlog(char *fmt,...)  {    va_list argptr;    FILE *fp;    fp = fopen(DAEMON_LOG, "a+t ");    va_start(argptr,fmt);    vfprintf(fp,fmt,argptr);    va_end(argptr);    fclose(fp); 

MegaEntry 网络社区与信息交流平台!

}  pid_t CheckLock(void)  {    pid_t me;    FILE * fp;    fp = fopen(DAEMON_LOCK, "rt ");    if (fp==NULL) return 0;    fscanf(fp, "%d ",&me);    fclose(fp);    return me;  }  pid_t WriteLock(void) 

文章版权归原作者所有! (www.MegaEntry.com)

{    pid_t me;    FILE *fp;    me = getpid();    fp = fopen(DAEMON_LOCK, "w ");    fprintf(fp, "%d ",me);    fclose(fp);    return me;  }  int CleanLock(void)  {    return (unlink(DAEMON_LOCK)==0); 

MegaEntry 网络社区与信息交流平台!

}  void report_time(void)  {    time_t now;    now = time(NULL);    dlog( "%s ",asctime((const struct tm*)localtime(&now)));  }  static void signal_catch(int signo)  {    time_t now;    close(DaemonSocket);    if (ClientSocket>0) close(ClientSocket);    CleanLock(); 

MegaEntry 网络社区与信息交流平台!

  now = time(NULL);    dlog( "Catch signal %d, leave at %s ",signo,asctime((const struct tm*)localti    exit(-1);  }  void SetupSignal(void)  {    struct sigaction act;    act.sa_handler = signal_catch;    act.sa_flags   = 0;    sigemptyset(&act.sa_mask);    sigaction(SIGHUP,&act,NULL);    sigaction(SIGINT,&act,NULL);    sigaction(SIGQUIT,&act,NULL);    sigaction(SIGILL,&act,NULL); 

文章版权归原作者所有! (www.MegaEntry.com)

  sigaction(SIGABRT,&act,NULL);    sigaction(SIGIOT,&act,NULL);    sigaction(SIGBUS,&act,NULL);    sigaction(SIGFPE,&act,NULL);    sigaction(SIGTERM,&act,NULL);  }  int BindSocket(void)  {    DaemonSocket = socket(AF_INET,SOCK_STREAM,0);    if (DaemonSocket==-1) return 0;    DaemonAddr.sin_family = AF_INET;    DaemonAddr.sin_port   = htons(DAEMON_PORT);    if (bind(DaemonSocket,&DaemonAddr,sizeof(DaemonAddr))<0) {      printf( "Can not bind! "); 

文章版权归原作者所有! (www.MegaEntry.com)

    return 0;    }    if (listen(DaemonSocket,1024)!=0) {      printf( "Can not listen! ");      return 0;    }    return 1;  }  int incoming_call(void)  {    fd_set sock;    struct timeval tv;    int t; 

文章版权归原作者所有! (www.MegaEntry.com)

  FD_ZERO(&sock);    FD_SET(DaemonSocket,&sock);    tv.tv_sec = 60; tv.tv_usec = 0;    t = select(DaemonSocket + 1,&sock,NULL,NULL,&tv);    if (t<=0||!FD_ISSET(DaemonSocket,&sock)) return 0;    dlog( "incoming... ");    return 1;  }  int ConnectClient(void)  {    int socksize=sizeof(HostAddr);    unsigned char * addr; 

MegaEntry 网络社区与信息交流平台!

  ClientSocket = accept(DaemonSocket,(struct sockaddr*)&HostAddr,&socksize);    if (ClientSocket<0) return 0;    addr = (unsigned char *)&HostAddr.sin_addr.s_addr;    dlog( "incoming address:%d.%d.%d.%d ",addr[0],addr[1],addr[2],addr[3]);    return 1;  }  int daemon_printf(char *fmt,...)  {    char BUF[4096];    va_list argptr;    va_start(argptr,fmt); 

MegaEntry 网络社区与信息交流平台!

  vsprintf(BUF,fmt,argptr);    va_end(argptr);    return write(ClientSocket,BUF,strlen(BUF));  }  void Log(void)  {    char BUF[4096];    read(DaemonSocket,BUF,16);    daemon_printf( "%s ",BUF[0]);  }  int main(int argc,char **argv)  {    pid_t myself;    time_t now; 

MegaEntry 网络社区与信息交流平台!

  /* find myself */    myself = CheckLock();    if (myself!=0) {      printf( "Existing a copy of chess daemon[pid=%d], leave now. ",myself);      exit(1);    }    /* fork */    myself = fork();    if (myself>0) {      exit(1);    } else    if (myself<0) {      printf( "Strange world! I don 't like it. Quit because of pid=%d ",myself);      exit(1); 

文章版权归原作者所有! (www.MegaEntry.com)

  } else {      SetupSignal();      if (!BindSocket()) {        printf( "Can not bind socket! ");        exit(1);      }      WriteLock();    }    printf( "Chess Daemon is up, have fun! ");    now = time(NULL);    dlog( "---------------------------------------------- ");    dlog(       "I am back! %s " 

MegaEntry 网络社区与信息交流平台!

     "Chess Daemon comes to alive again. ",      asctime((const struct tm*)localtime(&now))    );    do {      if (incoming_call()) {        if (ConnectClient()) {          fd_set sock;          struct timeval tv;          int t;          char BUF[128];          char CC[2];          int n; 

MegaEntry 网络社区与信息交流平台!

          daemon_printf( "Welcome to Chinese Chess Game Center! ");            FD_ZERO(&sock);            FD_SET(ClientSocket,&sock);            n = 0;            do {              tv.tv_sec = 60; tv.tv_usec = 0;              t = select(ClientSocket+1,&sock,NULL,NULL,&tv);              if (t<=0||!FD_ISSET(ClientSocket,&sock)) ;              read(ClientSocket,CC,1);              if (CC[0]==13||CC[0]==10||CC[0]==0) {                BUF[n] = 0;                dlog( "%s ",BUF);                if (strncasecmp(BUF, "exit ",4)==0) {                  close(ClientSocket);                  break; 

MegaEntry 网络社区与信息交流平台!

              }                n = 0;              } else {                BUF[n]=CC[0]; n++;              }            } while (1);        }      }    } while (1);    return 1;  }  检验 telnet localhost 9901    

文章版权归原作者所有! (www.MegaEntry.com)

在处理Connect Client时,事实上可以运用fork或thread来处理多个连线。 

上一篇:Linux程式设计- 5.inetd下一篇:Linux程式设计- 3.signals

回复
标题: 

强烈建议采用IE 6.0或以上的浏览器