1. 程式人生 > >循序漸進學unix——上機記錄(七),socket

循序漸進學unix——上機記錄(七),socket

本次的主題是基本網路程式設計:socket,涉及到的概念比較多,就不詳細展開了。從程式設計角度簡單的說,為了在客戶端和伺服器之間建立一個連線,伺服器端需要依次呼叫這些函式:

  1. socket,獲得一個socket
  2. bind,將獲得的socket繫結到指定的地址和埠
  3. listen,讓此socket進入等待狀態,等待客戶端的連線
  4. accept,當建立起與客戶端之間的連線時,此函式返回代表此連線的socket。即類似於檔案描述符,我們可以把客戶端看作檔案,向網路上進行讀寫操作,從而完成通訊過程。
客戶端需要呼叫的函式:
  1. socket
  2. connect,向指定地址的伺服器的指定埠發起連線
伺服器和客戶端都需用到的通訊函式:
  1. send
  2. recv
詳細資訊和函式方法等就不贅述了,請參見man 文件。
下面來看幾道練習。 1. 從客戶端把使用者輸入的資訊傳送到伺服器,直到使用者輸入“over”。這是一道基礎題,直接上程式碼了。 server:
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	int numPort, lenMsg, i;
	int sockServ, sockClient;
	struct sockaddr_in adrServ, adrClient;
	char message[256];
	char * overMsg = "over";
	int adrSize = sizeof(adrClient);
	int yes = 1;

	if(argc < 2)
	{
		printf("syntaxe : %s numPort\n", argv[0]);
		return -1;
	}
	

	//set local addr and port
	numPort = atoi(argv[1]);
	adrServ.sin_addr.s_addr = INADDR_ANY;
	adrServ.sin_family = AF_INET;
	adrServ.sin_port = htons(numPort);
	bzero(&(adrServ.sin_zero), 8) ;
	
	//Get a socket
	if((sockServ = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("sockServet"); return -1; }
	
	//We can set some param here.// paramètrage de la socket pour réutiliser le N° ce port sans délai
	if(setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); return -1; }

	// bind
	if(bind(sockServ, (struct sockaddr *)(&adrServ), sizeof(adrServ)) == -1) { perror("bind"); return -1; }

	// place la socket en écoute
	if(listen(sockServ, 1) == -1) { perror("listen"); return -1; }
	

	// wait for a connection from a client
	if((sockClient = accept(sockServ, (struct sockaddr *)(&adrClient), &adrSize)) == -1) { perror("accept"); return -1; }
	printf("New socket client : %s\n", inet_ntoa(adrClient.sin_addr));
	do
	{
		// Read a msg from client
		if((lenMsg = recv(sockClient, message, 256, 0)) == -1)
		{ perror("recv"); return -1; }
		message[lenMsg] = '\0';
		printf("New msg received : %s\n", message);
		//printf("New msg received : %s, %d\n", message, strcmp(message, overMsg));
		
	}while(strcmp(message, overMsg) != 0);	
	// fermeture de la connexion
	close(sockServ);
	
	return 0;
}


client:
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
void main(int argc, char* argv[])
{
	if(argc < 3)
	{
		printf("Syntax:%s server_addr <portNum>\n", argv[0]);
		exit(0);
	}


	int fdSock;
	//get a socket
	if( (fdSock=socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket"); exit(1);}
	
	//config the address of the server to connect
	struct sockaddr_in addrServer;
	addrServer.sin_family = AF_INET;//Address family
	inet_pton(AF_INET, argv[1], &(addrServer.sin_addr));//Convert the addr from "presentation" to "numeric"
	addrServer.sin_port=htons(atoi(argv[2]));//set the port number
	//Connect to server
	if( connect( fdSock, (struct sockaddr *)(&addrServer), sizeof(addrServer))== -1){perror("connect"); exit(1);}
	
	char buf[1024];
	gets(buf);//get a msg from terminal
	while(buf[0] != '\0')
	{
		printf("Gets gets : %s\n", buf);
		//Send the msg to server. See also "sendto" and "sendmsg"
		if( send(fdSock, buf, strlen(buf), 0) == -1){perror("Send"); exit(1);}
		if(strcmp(buf, "over") == 0)
		{
			printf("Exit...\n");
			close(fdSock);
			exit(0);
		}
		gets(buf);
	}


}
執行結果:
client:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./client12 127.0.0.1 9999
hello
Gets gets : hello
byebye
Gets gets : byebye
over
Gets gets : over
Exit...
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ 

server:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./server12 9999
New socket client : 127.0.0.1
New msg received : hello
New msg received : byebye
New msg received : over
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ 




2. 這次結合上exec,從客戶端傳送命令到伺服器,伺服器在本地執行命令。
server:
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define MAX_NUM_ARG 10
void exeCmd(char * cmd);

int main(int argc, char *argv[])
{
	int numPort, lenMsg, i;
	int sockServ, sockClient;
	struct sockaddr_in adrServ, adrClient;
	char message[256];
	char * overMsg = "over";
	int adrSize = sizeof(adrClient);
	int yes = 1;

	if(argc < 2)
	{
		printf("syntaxe : %s numPort\n", argv[0]);
		return -1;
	}
	

	//set local addr and port
	numPort = atoi(argv[1]);
	adrServ.sin_addr.s_addr = INADDR_ANY;
	adrServ.sin_family = AF_INET;
	adrServ.sin_port = htons(numPort);
	bzero(&(adrServ.sin_zero), 8) ;
	
	//Get a socket
	if((sockServ = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("sockServet"); return -1; }
	
	//We can set some param here.// paramètrage de la socket pour réutiliser le N° ce port sans délai
	if(setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); return -1; }

	// bind
	if(bind(sockServ, (struct sockaddr *)(&adrServ), sizeof(adrServ)) == -1) { perror("bind"); return -1; }

	// place la socket en écoute
	if(listen(sockServ, 1) == -1) { perror("listen"); return -1; }
	

	// wait for a connection from a client
	if((sockClient = accept(sockServ, (struct sockaddr *)(&adrClient), &adrSize)) == -1) { perror("accept"); return -1; }
	printf("New socket client : %s\n", inet_ntoa(adrClient.sin_addr));
	do
	{
		// Read a cmd from client
		if((lenMsg = recv(sockClient, message, 256, 0)) == -1)
			{ perror("recv"); return -1; }
		message[lenMsg] = '\0';
		printf("\nNew cmd received : %s, result:\n", message);
		exeCmd(message);
		//printf("New msg received : %s, %d\n", message, strcmp(message, overMsg));
		
	}while(strcmp(message, overMsg) != 0);	
	// fermeture de la connexion
	close(sockServ);
	
	return 0;
}


void exeCmd(char * cmd)
{
	if(fork()==0)
	{
		char *argv[MAX_NUM_ARG] = {NULL};
		int i;
		char *arg;
		for(i=0; i<MAX_NUM_ARG; i++)
		{
			if(i>0) cmd = NULL;
			arg = strtok(cmd, " ");
			if(arg != NULL)
			{
				//put this arg into argv[]
				argv[i] = calloc( sizeof(char), strlen(arg+1)) ;
				strcpy(argv[i], arg);
			}
			else
			{//execute this cmd
				execvp(argv[0], argv);
				exit(0);
			}
			
		}
		exit(0);
	}
}

client:
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
void main(int argc, char* argv[])
{
	if(argc < 3)
	{
		printf("Syntax:%s server_addr <portNum>\n", argv[0]);
		exit(0);
	}

	int fdSock;
	//get a socket
	if( (fdSock=socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket"); exit(1);}
	
	//config the address of the server to connect
	struct sockaddr_in addrServer;
	addrServer.sin_family = AF_INET;//Address family
	inet_pton(AF_INET, argv[1], &(addrServer.sin_addr));//Convert the addr from "presentation" to "numeric"
	addrServer.sin_port=htons(atoi(argv[2]));//set the port number
	//Connect to server
	if( connect( fdSock, (struct sockaddr *)(&addrServer), sizeof(addrServer))== -1){perror("connect"); exit(1);}
	
	char buf[1024];
	printf("\nexcute_cmd_in_distance$");
	gets(buf);//get a cmd from terminal
	while(buf[0] != '\0')
	{
		//printf("Gets gets : %s\n", buf);
		//Send the msg to server. See also "sendto" and "sendmsg"
		if( send(fdSock, buf, strlen(buf), 0) == -1){perror("Send"); exit(1);}
		if(strcmp(buf, "over") == 0)
		{
			printf("Exit...\n");
			close(fdSock);
			exit(0);
		}
		printf("\nexcute_cmd_in_distance$");
		gets(buf);
	}

}

執行結果: client:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./client3 127.0.0.1 9999

excute_cmd_in_distance$ls

excute_cmd_in_distance$ls -l

excute_cmd_in_distance$pwd

excute_cmd_in_distance$over
Exit...
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ 

server:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./server3 9999
New socket client : 127.0.0.1

New cmd received : ls, result:
12_client.c  3_client.c  client   client12  in.h      server3    td6-1_serveur-modif.c  types.h
12_server.c  3_server.c  client1  client3   server12  socket.h    td6.pdf

New cmd received : ls -l, result:
total 152
-rw-r--r-- 1 administrateur administrateur  1171 déc.  26 12:39 12_client.c
-rw-r--r-- 1 administrateur administrateur  1842 déc.  26 12:36 12_server.c
-rw-r--r-- 1 administrateur administrateur  1250 déc.  26 13:28 3_client.c
-rw-r--r-- 1 administrateur administrateur  2323 déc.  26 13:28 3_server.c
-rw-r--r-- 1 administrateur administrateur  7563 déc.   5 15:17 client
-rwxrwxr-x 1 administrateur administrateur  7549 déc.  26 11:47 client1
-rwxrwxr-x 1 administrateur administrateur  7623 déc.  26 12:31 client12
-rwxrwxr-x 1 administrateur administrateur  7622 déc.  26 13:28 client3
-rw-r--r-- 1 administrateur administrateur 18637 janv. 22  2011 in.h
-rwxrwxr-x 1 administrateur administrateur  7668 déc.  26 12:36 server12
-rwxrwxr-x 1 administrateur administrateur  7914 déc.  26 13:28 server3
-rw-r--r-- 1 administrateur administrateur  9597 janv. 22  2011 socket.h
-rw-r--r-- 1 administrateur administrateur  1953 déc.  26 11:46 td6-1_serveur-modif.c
-rw-r--r-- 1 administrateur administrateur 44356 nov.  30 15:39 td6.pdf
-rw-r--r-- 1 administrateur administrateur  6838 janv. 22  2011 types.h

New cmd received : pwd, result:
/home/administrateur/Bureau/POLYTECH/unix/TD UNIX2012/td6

New cmd received : over, result:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ 



3. 理解”一切皆檔案“的概念。將server的標準輸入輸出重定向到client,即從client讀取命令字串,並將執行結果返回給client輸出。到這裡不難發現我們所要做的有點像個遠端終端。 並無特殊,加上重定向(在執行命令的子程序中)即可。 server:
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define MAX_NUM_ARG 10
void exeCmd(int sockClient, char * cmd)
{
	
	if(fork()==0)
	{
		//Set redirection
		dup2(sockClient, 0);
		dup2(sockClient, 1);
		close(sockClient);

		char *argv[MAX_NUM_ARG] = {NULL};
		int i;
		char *arg;
		for(i=0; i<MAX_NUM_ARG; i++)
		{
			if(i>0) cmd = NULL;
			arg = strtok(cmd, " ");
			if(arg != NULL)
			{
				//put this arg into argv[]
				//argv[i] = calloc( sizeof(char), strlen(arg+1)) ;
				//strcpy(argv[i], arg);
				argv[i] = arg;//We can also simply do like this.
				fprintf(stderr, "cmd[%d] = %s\n",i,arg);
			}
			else
			{//execute this cmd
				execvp(argv[0], argv);
				exit(0);
			}
			
		}
		exit(0);
	}
}

int main(int argc, char *argv[])
{
	

	int numPort, lenMsg, i;
	int sockServ, sockClient;
	struct sockaddr_in adrServ, adrClient;
	char message[256];
	char * overMsg = "over";
	int adrSize = sizeof(adrClient);
	int yes = 1;

	if(argc < 2)
	{
		printf("syntaxe : %s numPort\n", argv[0]);
		return -1;
	}
	

	//set local addr and port
	numPort = atoi(argv[1]);
	adrServ.sin_addr.s_addr = INADDR_ANY;
	adrServ.sin_family = AF_INET;
	adrServ.sin_port = htons(numPort);
	bzero(&(adrServ.sin_zero), 8) ;
	
	//Get a socket
	if((sockServ = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("sockServet"); return -1; }
	
	//We can set some param here.// paramètrage de la socket pour réutiliser le N° ce port sans délai
	if(setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); return -1; }

	// bind
	if(bind(sockServ, (struct sockaddr *)(&adrServ), sizeof(adrServ)) == -1) { perror("bind"); return -1; }

	// place la socket en écoute
	if(listen(sockServ, 1) == -1) { perror("listen"); return -1; }
	

	// wait for a connection from a client
	if((sockClient = accept(sockServ, (struct sockaddr *)(&adrClient), &adrSize)) == -1) { perror("accept"); return -1; }
	printf("New socket client : %s\n", inet_ntoa(adrClient.sin_addr));

	do
	{
		// Read a cmd from client
		//fgets(stdin, message);
		//fscanf(sockClient,"%s",message);
		if((lenMsg = recv(sockClient, message, 256, 0)) == -1)
			{ perror("recv"); return -1; }
		else if (lenMsg == 0)
		{
			close(sockClient);
			return 0;
		}
		message[lenMsg] = '\0';
		printf("New cmd received : %s\n", message);
		exeCmd(sockClient, message);
		//fflush(sockClient);
		//printf("New msg received : %s, %d\n", message, strcmp(message, overMsg));
		
	}while(strcmp(message, overMsg) != 0);	
	// fermeture de la connexion
	close(sockClient);
	
	return 0;
}
server執行結果:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./server4 9999
New socket client : 127.0.0.1
New cmd received : ls
cmd[0] = ls
New cmd received : pwd
cmd[0] = pwd
New cmd received : date
cmd[0] = date
New cmd received : ls -l
cmd[0] = ls
cmd[1] = -l
New cmd received : over
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ cmd[0] = over

client:
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
void main(int argc, char* argv[])
{
	if(argc < 3)
	{
		printf("Syntax:%s server_addr <portNum>\n", argv[0]);
		exit(0);
	}

	int fdSock, res;
	//get a socket
	if( (fdSock=socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket"); exit(1);}
	
	//config the address of the server to connect
	struct sockaddr_in addrServer;
	addrServer.sin_family = AF_INET;//Address family
	inet_pton(AF_INET, argv[1], &(addrServer.sin_addr));//Convert the addr from "presentation" to "numeric"
	addrServer.sin_port=htons(atoi(argv[2]));//set the port number
	//Connect to server
	if( connect( fdSock, (struct sockaddr *)(&addrServer), sizeof(addrServer))== -1){perror("connect"); exit(1);}
	
	char buf[1024];
	printf("\nexcute_cmd_in_distance$");
	gets(buf);//get a cmd from terminal
	while(buf[0] != '\0')
	{
		//printf("Gets gets : %s\n", buf);
		//Send the msg to server. See also "sendto" and "sendmsg"
		if( send(fdSock, buf, strlen(buf), 0) == -1){perror("Send"); exit(1);}
		if(strcmp(buf, "over") == 0)
		{
			printf("Exit...\n");
			close(fdSock);
			exit(0);
		}
		if( (res = recv(fdSock, buf, 1024, 0)) == -1){perror("recv"); exit(1);}
		else if(res == 0) {close(fdSock); exit(0);}
		else
		{
			buf[res] = '\0';
			printf("\n%s",buf);
		}
		printf("\nexcute_cmd_in_distance$");
		gets(buf);
	}

}

client執行結果:
/home/administrateur/Bureau/POLYTECH/unix/TD UNIX2012/td6

excute_cmd_in_distance$date

mercredi 26 décembre 2012, 17:10:46 (UTC+0100)

excute_cmd_in_distance$ls -l

total 88
-rw-r--r-- 1 administrateur administrateur  1171 déc.  26 12:39 12_client.c
-rw-r--r-- 1 administrateur administrateur  1842 déc.  26 12:36 12_server.c
-rw-r--r-- 1 administrateur administrateur  1250 déc.  26 13:28 3_client.c
-rw-r--r-- 1 administrateur administrateur  2323 déc.  26 13:28 3_server.c
-rw-r--r-- 1 administrateur administrateur  1433 déc.  26 17:10 4_client.c
-rw-r--r-- 1 administrateur administrateur  2626 déc.  26 17:06 4_server.c
-rwxrwxr-x 1 administrateur administrateur  7658 déc.  26 17:10 client4
drwxrwxr-x 2 administrateur administrateur  4096 déc.  26 14:54 doc
-rwxrwxr-x 1 administrateur administrateur  7947 déc.  26 17:10 server4
-rw-r--r-- 1 administrateur administrateur 44356 nov.  30 15:39 td6.pdf

excute_cmd_in_distance$over
Exit...
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ 

5. 在第4題的基礎上,我們考慮I/O多路複用。試想,當client傳送完命令,並且正在等待執行結果的時候,使用者又在終端輸入了一條命令。由於程式被recv阻塞,使用者輸入的命令並不會被處理。有沒有一種方法可以監聽所有的io操作,並在任何一個操作結束阻塞的時候通知我們呢?沒錯,我們在談select和poll函式。下面的實現使用了poll函式,請注意看它是如何同時監聽所有io並在任何一個io操作準備就緒時返回的。 client:
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
#include<poll.h>
void main(int argc, char* argv[])
{
	if(argc < 3)
	{
		printf("Syntax:%s server_addr <portNum>\n", argv[0]);
		exit(0);
	}

	int fdSock, res, nready;
	//get a socket
	if( (fdSock=socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket"); exit(1);}
	
	//config the address of the server to connect
	struct sockaddr_in addrServer;
	addrServer.sin_family = AF_INET;//Address family
	inet_pton(AF_INET, argv[1], &(addrServer.sin_addr));//Convert the addr from "presentation" to "numeric"
	addrServer.sin_port=htons(atoi(argv[2]));//set the port number
	//Connect to server
	if( connect( fdSock, (struct sockaddr *)(&addrServer), sizeof(addrServer))== -1){perror("connect"); exit(1);}
	
	char buf[1024];
	printf("\nexcute_cmd_in_distance$");
	//gets(buf);//get a cmd from terminal
	
	//POLL added here
	struct pollfd pfds[2];
	bzero(pfds, sizeof(pfds[0]));	
	bzero(pfds+1, sizeof(pfds[0]));
	pfds[0].fd = 0;
	pfds[0].events = POLLRDNORM;//The event waited.(Normal read)

	pfds[1].fd = fdSock;
	pfds[1].events = POLLRDNORM;
	
	while(buf[0] != '\0')
	{
		printf("\nexcute_cmd_in_distance$");
		nready = poll(pfds, 2, -1);//nready is the number of ready fds
		if(pfds[0].revents & POLLRDNORM)
		{
			//deal with user input, send cmd to server
			gets(buf);
			if( send(fdSock, buf, strlen(buf), 0) == -1){perror("Send"); exit(1);}
			if(strcmp(buf, "over") == 0)
			{
				printf("Exit...\n");
				close(fdSock);
				exit(0);
			}
			
			pfds[0].revents = 0;
			nready --;
			if(nready == 0)
				continue;
		}
		if(pfds[1].revents & POLLRDNORM )
		{
			//deal with socket, display the result of the last cmd
			pfds[1].revents = 0;
				
			if( (res = recv(fdSock, buf, 1024, 0)) == -1){perror("recv"); exit(1);}
			else if(res == 0) {close(fdSock); exit(0);}
			else
			{
				buf[res] = '\0';
				printf("\n%s",buf);
			}
		}
		
	}

}

server:程式碼無太大變化,除了exeCmd函式。現在我們使用”bash“命令來執行其它命令。
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define MAX_NUM_ARG 10
void exeCmd(int sockClient, char * cmd)
{
	
	if(fork()==0)
	{
		//Set redirection
		dup2(sockClient, 0);
		dup2(sockClient, 1);
		close(sockClient);

		execlp("bash", "bash", "-c", cmd, NULL);
		exit(0);
	}
}

int main(int argc, char *argv[])
{
	

	int numPort, lenMsg, i;
	int sockServ, sockClient;
	struct sockaddr_in adrServ, adrClient;
	char message[256];
	char * overMsg = "over";
	int adrSize = sizeof(adrClient);
	int yes = 1;

	if(argc < 2)
	{
		printf("syntaxe : %s numPort\n", argv[0]);
		return -1;
	}
	

	//set local addr and port
	numPort = atoi(argv[1]);
	adrServ.sin_addr.s_addr = INADDR_ANY;
	adrServ.sin_family = AF_INET;
	adrServ.sin_port = htons(numPort);
	bzero(&(adrServ.sin_zero), 8) ;
	
	//Get a socket
	if((sockServ = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("sockServet"); return -1; }
	
	//We can set some param here.// paramètrage de la socket pour réutiliser le N° ce port sans délai
	if(setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); return -1; }

	// bind
	if(bind(sockServ, (struct sockaddr *)(&adrServ), sizeof(adrServ)) == -1) { perror("bind"); return -1; }

	// place la socket en écoute
	if(listen(sockServ, 1) == -1) { perror("listen"); return -1; }
	

	// wait for a connection from a client
	if((sockClient = accept(sockServ, (struct sockaddr *)(&adrClient), &adrSize)) == -1) { perror("accept"); return -1; }
	printf("New socket client : %s\n", inet_ntoa(adrClient.sin_addr));

	
	do
	{
		if((lenMsg = recv(sockClient, message, 256, 0)) == -1)
			{ perror("recv"); return -1; }
		else if (lenMsg == 0)
		{
			close(sockClient);
			return 0;
		}
		message[lenMsg] = '\0';
		printf("New cmd received : %s\n", message);
		exeCmd(sockClient, message);
		
	}while(strcmp(message, overMsg) != 0);	
	// fermeture de la connexion
	close(sockClient);
	
	return 0;
}

執行結果: client:每條命令下顯示的結果其實是在server端執行的。你發現什麼變化沒有?當我們執行find / -name "socket.h" 這條耗時的命令後,server端並不能馬上返回結果,而我們仍可以馬上執行下一條命令:date,並且我們先得到了date的結果,之後才是find命令的搜尋結果。
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./4_client 127.0.0.1 9999

ls
excute_cmd_in_distance$
12_client.c
12_server.c
3_client.c
3_server.c
4
4_client
4_client.c
4_poll_client.c
4_poll_client.c~
4_poll_server.c
4_poll_server.c~
4_server.c
4_server.c~
client4
clientPoll
doc
server4
td6.pdf

sudo find / -name "socket.h"
excute_cmd_in_distance$date

mercredi 26 décembre 2012, 17:53:30 (UTC+0100)

excute_cmd_in_distance$
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/alpha/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/arm/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/avr32/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/blackfin/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/cris/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/frv/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/h8300/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/ia64/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/m32r/include/asm/socket.h
/media/DONNEES/Polytech/Tutorial/Linux/linux-2.6.33.20/linux-2.6.33.20/arch/m68k/include/asm/socket.h
excute_cmd_in_distance$

server:
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./4
syntaxe : ./4 numPort
[email protected]:~/Bureau/POLYTECH/unix/TD UNIX2012/td6$ ./4 9999
New socket client : 127.0.0.1
New cmd received : ls
New cmd received : sudo find / -name "socket.h"
[sudo] password for administrateur: 
New cmd received : date

可以看出server先後收到的所有命令。另外,由於重定向是在子程序中做得,所以要求輸入密碼的那行並沒有傳送給客戶端而是在本地顯示了。