#include <stdio.h> #include <stdlib.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <memory.h> #include <unistd.h> //#include <linux/in.h> #include <netinet/in.h> //#include <linux/inet_diag.h> #include <arpa/inet.h> #include <signal.h> /** 關(guān)于 sockaddr sockaddr_in socketaddr_un說明 http://maomaozaoyue.blog.sohu.com/197538359.html */ #define PORT 11910 //定義通信端口 #define BACKLOG 5 //定義偵聽隊列長度 #define buflen 1024 void process_conn_server(int s); void sig_pipe(int signo); int ss,sc; //ss為服務(wù)器socket描述符,sc為某一客戶端通信socket描述符 int main(int argc,char *argv[]) { struct sockaddr_in server_addr; //存儲服務(wù)器端socket地址結(jié)構(gòu) struct sockaddr_in client_addr; //存儲客戶端 socket地址結(jié)構(gòu) int err; //返回值 pid_t pid; //分叉進(jìn)行的ID /*****************socket()***************/ ss = socket(AF_INET,SOCK_STREAM,0); //建立一個序列化的,可靠的,雙向連接的的字節(jié)流 if(ss<0) { printf(" server : server socket create error\n"); return -1; } //注冊信號 sighandler_t ret; ret = signal(SIGTSTP,sig_pipe); if(SIG_ERR == ret) { printf("信號掛接失敗\n"); return -1; } else printf("信號掛接成功\n"); /******************bind()****************/ //初始化地址結(jié)構(gòu) memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; //協(xié)議族 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本地地址 server_addr.sin_port = htons(PORT); err = bind(ss,(struct sockaddr *)&server_addr,sizeof(sockaddr)); if(err<0) { printf("server : bind error\n"); return -1; } /*****************listen()***************/ err = listen(ss,BACKLOG); //設(shè)置監(jiān)聽的隊列大小 if(err < 0) { printf("server : listen error\n"); return -1; } /****************accept()***************/ /** 為類方便處理,我們使用兩個進(jìn)程分別管理兩個處理: 1,服務(wù)器監(jiān)聽新的連接請求;2,以建立連接的C/S實現(xiàn)通信 這兩個任務(wù)分別放在兩個進(jìn)程中處理,為了防止失誤操作 在一個進(jìn)程中關(guān)閉 偵聽套接字描述符 另一進(jìn)程中關(guān)閉 客戶端連接套接字描述符。注只有當(dāng)所有套接字全都關(guān)閉時 當(dāng)前連接才能關(guān)閉,fork調(diào)用的時候父進(jìn)程與子進(jìn)程有相同的 套接字,總共兩套,兩套都關(guān)閉掉才能關(guān)閉這個套接字 */ for(;;) { socklen_t addrlen = sizeof(client_addr); //accept返回客戶端套接字描述符 sc = accept(ss,(struct sockaddr *)&client_addr,&addrlen); //注,此處為了獲取返回值使用 指針做參數(shù) if(sc < 0) //出錯 { continue; //結(jié)束此次循環(huán) } else { printf("server : connected\n"); } //創(chuàng)建一個子線程,用于與客戶端通信 pid = fork(); //fork 調(diào)用說明:子進(jìn)程返回 0 ;父進(jìn)程返回子進(jìn)程 ID if(pid == 0) //子進(jìn)程,與客戶端通信 { close(ss); process_conn_server(sc); } else { close(sc); } } } /** 服務(wù)器對客戶端連接處理過程;先讀取從客戶端發(fā)送來的數(shù)據(jù), 然后將接收到的數(shù)據(jù)的字節(jié)的個數(shù)發(fā)送到客戶端 */ //通過套接字 s 與客戶端進(jìn)行通信 void process_conn_server(int s) { ssize_t size = 0; char buffer[buflen]; //定義數(shù)據(jù)緩沖區(qū) for(;;) { //等待讀 for(size = 0;size == 0 ;size = read(s,buffer,buflen)); //輸出從客戶端接收到的數(shù)據(jù) printf("%s",buffer); //結(jié)束處理 if(strcmp(buffer,"quit") == 0) { close(s); //成功返回0,失敗返回-1 return ; } sprintf(buffer,"%d bytes altogether\n",size); write(s,buffer,strlen(buffer)+1); } } void sig_pipe(int signo) { printf("catch a signal\n"); if(signo == SIGTSTP) { printf("接收到 SIGTSTP 信號\n"); int ret1 = close(ss); int ret2 = close(sc); int ret = ret1>ret2?ret1:ret2; if(ret == 0) printf("成功 : 關(guān)閉套接字\n"); else if(ret ==-1 ) printf("失敗 : 未關(guān)閉套接字\n"); exit(1); } } |