[ 永远的UNIX::UNIX技术资料的宝库 ]

首页 > 编程技术 > 其它 > 正文
Linux程式设计- 4.socket
http://www.openchess.org/noitatsko/programming/ (2001-05-24 17:24:26)
UNIX Socket Programming基本上是一本书名。Socket programming其实需要相当程度的基础,我不想在这包山包海地,如果您需要彻底研究,可以买这本书来看。在此我想提供一些简单的Server/Client两端的简单写法,让你有个起点,做为进一步研究的基础。很多涉及较复杂的内容的,我在这便不详细说明,您可以照本宣科,照抄着用,稍微熟悉时,再细细研究。 

--------------------------------------------------------------------------------

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)); 
  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  
#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; 
  

  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); 
  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); 
  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
要建立起一个网路伺服器,第一步就是要"倾远方",也就是要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!\n"); 
    return 0; 
  } 
  if (listen(DaemonSocket,1024)!=0) { 
    printf("Can not listen!\n"); 
    return 0; 
  } 

  return 1; 


Incoming call
要查看是否有连线进来,可用以下方式: 
int incoming_call(void) 

  fd_set sock; 
  struct timeval tv; 
  int t; 

  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; 

  printf("incoming...\n"); 

  return 1; 


Connect Client
当我们确认有人进来要求服务时,会需要accept connection,可用以下方式 
int ConnectClient(void) 

  int socksize=sizeof(HostAddr); 
  unsigned char * addr; 

  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\n",addr[0],addr[1],addr[2],addr[3]); 

  return 1; 


注意到当您accept connection之後,连线已建立起,此时要用的socket是ClientSocket,而非DaemonSocket,ClientSocket才是真正用来连线用的socket。 

这是个我才刚开始动手写的象棋伺服器。 

#include  
#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 

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); 


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) 

  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); 


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(); 
  now = time(NULL); 
  dlog("Catch signal %d, leave at %s\n",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); 
  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!\n"); 
    return 0; 
  } 
  if (listen(DaemonSocket,1024)!=0) { 
    printf("Can not listen!\n"); 
    return 0; 
  } 

  return 1; 


int incoming_call(void) 

  fd_set sock; 
  struct timeval tv; 
  int t; 

  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...\n"); 

  return 1; 


int ConnectClient(void) 

  int socksize=sizeof(HostAddr); 
  unsigned char * addr; 

  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\n",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); 
  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; 

  /* find myself */ 
  myself = CheckLock(); 
  if (myself!=0) { 
    printf("Existing a copy of chess daemon[pid=%d], leave now.\n",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\n",myself); 
    exit(1); 
  } else { 
    SetupSignal(); 
    if (!BindSocket()) { 
      printf("Can not bind socket!\n"); 
      exit(1); 
    } 
    WriteLock(); 
  } 

  printf("Chess Daemon is up, have fun!\n"); 

  now = time(NULL); 

  dlog("----------------------------------------------\n"); 
  dlog( 
    "I am back! %s" 
    "Chess Daemon comes to alive again.\n", 
    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; 

          daemon_printf("Welcome to Chinese Chess Game Center!\n"); 

          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\n",BUF); 
              if (strncasecmp(BUF,"exit",4)==0) { 
                close(ClientSocket); 
                break; 
              } 
              n = 0; 
            } else { 
              BUF[n]=CC[0]; n++; 
            } 
          } while (1); 
      } 
    } 
  } while (1); 

  return 1; 


检验
telnet localhost 9901 
  
在处理Connect Client时,事实上可以运用fork或thread来处理多个连线。 
(http://www.fanqiang.com)
    进入【UNIX论坛

相关文章
Linux程式设计-31.工作群资讯管理(grp) (2001-05-27 22:08:00)
Linux程式设计-30.使用者资讯管理(pwd) (2001-05-27 21:04:00)
Linux程式设计-29.时间处理 (2001-05-27 20:10:01)
Linux程式设计-28.GNU Make (2001-05-27 19:00:00)
Linux程式设计-27.GNU Debugger (2001-05-27 18:08:01)
Linux程式设计-26.PIPE (2001-05-27 17:04:00)
Linux程式设计-25.Message Queues (2001-05-27 16:10:00)
Linux程式设计-24.Semaphores (2001-05-27 15:00:00)
Linux程式设计-23.共享记忆体(Shared Memory) (2001-05-27 14:08:00)
Linux程式设计-20.getopt (2001-05-27 13:04:00)

===更多相关===
 

★  樊强制作 欢迎分享  ★