同一機器上的不一樣進程之間的通訊方式有不少種,主要使用消息傳遞或共享內存。而跨網絡的進程是幾乎都是使用socket通訊,例如web服務器,QQ。html
socket便是一種特殊的文件,操做系統提供了一些socket函數就是對其進行的操做(讀/寫IO、打開、關閉),進程間的通訊就是靠讀寫各自的socket完成的。linux
通訊的過程web
server:編程
注意:server最初會建立一個socktet,收到鏈接請求後(accept())以後會建立一個與原有的命名套接字不一樣的套接字。這個新的套接字只與這個特定的client通訊,而命名套接字會保留下來繼續處理來自client的鏈接。服務器
client:網絡
1. int socket(int domain, int type, int protocol); 建立指定類型的socket,兩個進程可以通訊,必須使用相同域和類型的套接字。dom
2. int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);socket
地址格式:ide
struct sockaddr_in {函數
sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ };
注意:一般服務器在啓動的時候都會綁定一個衆所周知的地址(如ip地址+端口號),用於提供服務,客戶就能夠經過它來接連服務器;而客戶端就不用指定,有系統自動分配一個端口號和自身的ip地址組合。
這就是爲何一般服務器端在listen以前會調用bind(),而客戶端就不會調用,而是在connect()時由系統隨機生成一個。
3.其它
3、簡單易學的socket程序示例
一個簡單的示例,建立AF_INET型域和SOCK_STREAM面向鏈接的socket字,server開啓服務,client請求鏈接,向server發送消息,server收到消息後,迴應client,結束鏈接,也關閉服務器。
代碼中有註釋,基本上是安裝前面socket通訊的步驟寫的代碼。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 9 void error(const char *msg) 10 { 11 perror(msg); 12 exit(1); 13 } 14 15 int main(int argc, char *argv[]) 16 { 17 int sockfd, newsockfd, portno; 18 socklen_t clilen; 19 char buffer[256]; 20 struct sockaddr_in serv_addr, cli_addr; 21 int n; 22 if (argc < 2) { 23 fprintf(stderr,"ERROR, no port provided\n"); 24 exit(1); 25 } 26 27 //create a socktet 28 sockfd = socket(AF_INET, SOCK_STREAM, 0); 29 if (sockfd < 0) 30 error("ERROR opening socket"); 31 32 //bind an address to that socktet 33 bzero((char *) &serv_addr, sizeof(serv_addr)); 34 portno = atoi(argv[1]); 35 serv_addr.sin_family = AF_INET; 36 serv_addr.sin_addr.s_addr = INADDR_ANY; 37 serv_addr.sin_port = htons(portno); 38 if (bind(sockfd, (struct sockaddr *) &serv_addr, 39 sizeof(serv_addr)) < 0) 40 error("ERROR on binding"); 41 42 // listen to the socktet 43 listen(sockfd,5); 44 45 //accept connection and create a corresponding new socket 46 clilen = sizeof(cli_addr); 47 newsockfd = accept(sockfd, 48 (struct sockaddr *) &cli_addr, 49 &clilen); 50 if (newsockfd < 0) 51 error("ERROR on accept"); 52 53 54 //communication with the new sockfd(read and write data) 55 bzero(buffer,256); 56 n = read(newsockfd,buffer,255); 57 if (n < 0) error("ERROR reading from socket"); 58 printf("Here is the message: %s\n",buffer); 59 n = write(newsockfd,"I got your message",18); 60 if (n < 0) error("ERROR writing to socket"); 61 62 //ends the connection 63 close(newsockfd); 64 65 //ends server 66 close(sockfd); 67 return 0; 68 }
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <netdb.h> 9 10 void error(const char *msg) 11 { 12 perror(msg); 13 exit(0); 14 } 15 16 int main(int argc, char *argv[]) 17 { 18 int sockfd, portno, n; 19 struct sockaddr_in serv_addr; 20 struct hostent *server; 21 22 char buffer[256]; 23 if (argc < 3) { 24 fprintf(stderr,"usage %s hostname port\n", argv[0]); 25 exit(0); 26 } 27 portno = atoi(argv[2]); 28 29 //create a socket 30 sockfd = socket(AF_INET, SOCK_STREAM, 0); 31 if (sockfd < 0) 32 error("ERROR opening socket"); 33 34 35 server = gethostbyname(argv[1]); 36 if (server == NULL) { 37 fprintf(stderr,"ERROR, no such host\n"); 38 exit(0); 39 } 40 bzero((char *) &serv_addr, sizeof(serv_addr)); 41 serv_addr.sin_family = AF_INET; 42 bcopy((char *)server->h_addr, 43 (char *)&serv_addr.sin_addr.s_addr, 44 server->h_length); 45 serv_addr.sin_port = htons(portno); 46 47 //connect 48 if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 49 error("ERROR connecting"); 50 printf("Please enter the message: "); 51 bzero(buffer,256); 52 fgets(buffer,255,stdin); 53 54 55 //write and read data 56 n = write(sockfd,buffer,strlen(buffer)); 57 if (n < 0) 58 error("ERROR writing to socket"); 59 bzero(buffer,256); 60 n = read(sockfd,buffer,255); 61 if (n < 0) 62 error("ERROR reading from socket"); 63 printf("%s\n",buffer); 64 65 66 //end this connection 67 close(sockfd); 68 return 0; 69 }
使用方法:./server 3000 ./client localhost 3000 通常使用2000~65536之間的端口號
上面的代碼雖然能讓人很快理解,進程之間的網絡通訊是怎麼進行的。可是server只是接收一次消息,就立刻結束退出。
而實際中的server是一直在運行的,而且可以同時接收多個client的訪問,典型的作法是server每次收到鏈接請求式都fork一個新的子進程來處理鏈接請求。
爲了不產生zombie進程,須要在程序中使用signal(SIGCHLD,SIG_IGN);使得父進程無視子進程的die。
改進後的代碼:
1 /* A simple server in the internet domain using TCP 2 The port number is passed as an argument 3 This version runs forever, forking off a separate 4 process for each connection 5 */ 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <sys/types.h> 11 #include <sys/socket.h> 12 #include <netinet/in.h> 13 #include <signal.h> 14 15 void dostuff(int); /* function prototype */ 16 void error(const char *msg) 17 { 18 perror(msg); 19 exit(1); 20 } 21 22 int main(int argc, char *argv[]) 23 { 24 int sockfd, newsockfd, portno, pid; 25 socklen_t clilen; 26 struct sockaddr_in serv_addr, cli_addr; 27 28 if (argc < 2) { 29 fprintf(stderr,"ERROR, no port provided\n"); 30 exit(1); 31 } 32 sockfd = socket(AF_INET, SOCK_STREAM, 0); 33 if (sockfd < 0) 34 error("ERROR opening socket"); 35 36 bzero((char *) &serv_addr, sizeof(serv_addr)); 37 portno = atoi(argv[1]); 38 serv_addr.sin_family = AF_INET; 39 serv_addr.sin_addr.s_addr = INADDR_ANY; 40 serv_addr.sin_port = htons(portno); 41 if (bind(sockfd, (struct sockaddr *) &serv_addr, 42 sizeof(serv_addr)) < 0) 43 error("ERROR on binding"); 44 45 listen(sockfd,5); 46 clilen = sizeof(cli_addr); 47 signal(SIGCHLD,SIG_IGN); 48 while (1) { 49 newsockfd = accept(sockfd, 50 (struct sockaddr *) &cli_addr, &clilen); 51 if (newsockfd < 0) 52 error("ERROR on accept"); 53 pid = fork(); 54 if (pid < 0) 55 error("ERROR on fork"); 56 if (pid == 0) { 57 //close(sockfd); 58 dostuff(newsockfd); 59 exit(0); 60 } 61 else close(newsockfd); 62 } /* end of while */ 63 close(sockfd); 64 return 0; /* we never get here */ 65 } 66 67 /******** DOSTUFF() ********************* 68 There is a separate instance of this function 69 for each connection. It handles all communication 70 once a connnection has been established. 71 *****************************************/ 72 void dostuff (int sock) 73 { 74 int n; 75 char buffer[256]; 76 77 bzero(buffer,256); 78 n = read(sock,buffer,255); 79 if (n < 0) error("ERROR reading from socket"); 80 printf("Here is the message: %s\n",buffer); 81 n = write(sock,"I got your message",18); 82 if (n < 0) error("ERROR writing to socket"); 83 }
socket幾乎是網絡間進程通訊的惟一手段,它的通訊是很是簡單而且重要的,須要記住。雖然在實際的大型的網絡服務器中,不會使用每次都使用socke系統調用t編程,而是使用包裝過的庫,可是仍是須要了解。
當讓要想成爲一個C++高手仍是須要熟悉某種網絡庫,能力強的話能夠本身包裝實現一個網絡庫。可是我以爲新手仍是先看看人家的庫~~如:好比boost-asio、好比libevent,boost-asio
參考:
1.http://www.linuxhowtos.org/C_C++/socket.htm?userrate=2
2.http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html