当前位置--> 首 页 --> 文 章 -->Linux Develop
|
|
※阅读文章※ |
Linux程式设计- 4.socket作者:不祥 [文章出自: www.fanqiang.com] 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来处理多个连线。 文章加入时间: 2004-11-17 14:56:32 责任编辑: w9 (3113 人次查阅) |