?? vcserver.c
字號:
/* vcserver.c server */
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in 結(jié)構(gòu)體 */
/* 下面的這個include可以使程序查詢主機(jī)名字列表,
找出所有與其IP綁定的hostname */
#include <netdb.h> /* 預(yù)定義/etc/hosts列表 */
main (int argc, char *argv[])
{
int rc, /* 系統(tǒng)調(diào)用return code */
new_sd, sock, /* server/listen 套接字標(biāo)識符 */
adrlen, /* sockaddr 長度 */
cnt; /* number of bytes I/O */
struct sockaddr_in myname; /* Internet套接字名稱 */
struct sockaddr_in *nptr; /* ptr 獲取端口號 */
struct sockaddr addr; /* 通用套接字名稱 */
char buf[80]; /* I/O 緩沖區(qū)定義 */
/* 在 /etc/hosts 文件中查找 */
struct hostent *hp, *gethostbyaddr();
/* 標(biāo)識服務(wù)器進(jìn)程,打印其PID */
printf("\nThis is the network server with pid %d\n",
getpid() );
/* 建立一個傾聽套接字 */
if (( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("network server socket failure %d\n", errno);
perror("network server");
exit(1);
}
/* 初始化套接字地址結(jié)構(gòu)中的各個參數(shù) */
myname.sin_family = AF_INET; /* Internet地址 */
myname.sin_port = 0; /* 系統(tǒng)會綁定端口號 */
myname.sin_addr.s_addr = INADDR_ANY;
/* 將IP地址結(jié)構(gòu)與套接字綁定,調(diào)用bind()函數(shù) */
if (bind(sock, &myname, sizeof(myname) ) < 0 ) {
close(sock); /* defensive programming */
printf("network server bind failure %d\n", errno);
perror("network server");
exit(2);
}
/* 獲取套接字端口號。調(diào)用getsockname()可以得到與套接字相關(guān)聯(lián)
的端口號,并作為套接字地址結(jié)構(gòu)中的一部分返回。記錄
這個端口號以供客戶端程序使用。
*/
adrlen = sizeof(addr); /* 地址長度為整形值 */
if ( ( rc = getsockname( sock, &addr, &adrlen ) ) < 0 )
{
printf("setwork server getsockname failure %d\n",
errno);
perror("network server");
close (sock);
exit(3);
}
/* 調(diào)試說明:
通用套接字地址addr被用來存放getsockname()返回的套接字的值。
打印這個信息。在一般的地址聲明中,除了地址族其余的都被定
義為字符串類型。Getsocknae()調(diào)用之后,這個通用套接字地址
結(jié)構(gòu)addr就會被用來存放關(guān)于客戶端進(jìn)程的信息。*/
printf("\nAfter getsockname():");
printf(" server listen socket data\n");
printf("\taddr.sa_family field value is: %d\n",
addr.sa_family);
printf("\taddr.sa_data string is %d bytes long;\n",
sizeof ( addr.sa_data ) );
printf("\taddr.sa_data string is:");
for ( cnt = 0; cnt < sizeof (addr.sa_data); cnt++)
printf(" %x", addr.sa_data[cnt]);
printf("\n");
/* 現(xiàn)在需要記錄下來套接字的端口號。在這里端口號將作為啟動客戶端程
序的一個命令行參數(shù)使用。 */
/* 注意指針nptr,它是指向通用套接字地址結(jié)構(gòu)的一個指針 */
nptr = (struct sockaddr_in *) &addr; /* port # */
printf("\n\tnetwork server: server has port number: %d\n",
ntohs ( nptr -> sin_port ) );
/* 調(diào)用listen()函數(shù) */
if ( listen ( sock, 5 ) < 0 ) {
printf("network server bind failure %d\n", errno);
perror("network server");
close (sock);
exit(4);
}
/* 調(diào)試輸出:
下面輸出結(jié)構(gòu)體myname中所包含的套接字信息 */
printf("Server has set up client socket with values:\n");
printf("\tInternet address is %lx\n", myname.sin_addr.s_addr);
printf("\tPort number used is %d\n", myname.sin_port);
printf("\tInternet family ID is %d\n", myname.sin_family);
printf("\tValues are filled in after connection request ");
printf("is accepted.");
/* 設(shè)置初始死循環(huán)以等待客戶端進(jìn)程的連接請求。由于結(jié)構(gòu)體myname已經(jīng)和傾聽套接字綁
定,通過accept()調(diào)用可以獲得套接字結(jié)構(gòu)名稱和套接字長度參數(shù)。 */
while (1) {
if ( ( new_sd = accept ( sock, 0, 0 ) ) < 0 ) {
printf("network server accept failure %d\n", errno);
perror("network server");
close (sock);
exit(5);
}
/* 通過fork()函數(shù)建立子進(jìn)程來處理客戶端服務(wù)請求。*/
if ( ( fork() ) == 0 ) { /* 子進(jìn)程 */
int pid;
pid = getpid(); /* 獲取子進(jìn)程的PID */
close (sock); /* 子進(jìn)程中不再需要父進(jìn)程的參與 */
/* 查找出客戶端所在。注意通用套接字地址結(jié)構(gòu)addr的用法,獲取客戶端信息 */
if ((rc = getpeername( new_sd, &addr, &adrlen )) < 0) {
printf("network server %d getpeername failure %d\n",
pid, errno);
perror("network server");
close(new_sd);
exit(6);
}
/* 答應(yīng)客戶端信息。由于指針nptr是一個sockaddr_in結(jié)構(gòu)體指針,
在這個結(jié)構(gòu)體中的地址名稱就可以傳遞給通用地址結(jié)構(gòu)體addr。 */
printf("\n\tnetwork server %d:", pid);
printf(" client socket from host %s\n",
inet_ntoa ( nptr -> sin_addr ) );
printf("\t has port number %d\n",nptr -> sin_port);
/* 現(xiàn)在找到了所有與客戶端相關(guān)的信息,并且可以通過在/etc/hosts
中查找來確定客戶端的域名 */
if (( hp = gethostbyaddr (&nptr -> sin_addr,4,AF_INET))
!= NULL ) {
printf ("\tfrom hostname: %s\n\twith aliases: ",
hp -> h_name );
while ( *hp -> h_aliases )
printf ("\n\t\t\t%s", *hp -> h_aliases++ );
printf("\n\n");
}
else {
printf("network server %d ", pid);
printf("gethostbyaddr failure %d\n", h_errno);
perror("network server");
}
/* 與客戶端交換數(shù)據(jù)。首先清除緩沖區(qū) */
do {
memset (buf,0,sizeof(buf)); /* 清空緩沖區(qū) */
/* bzero( buf, sizeof(buf));* 清空緩沖區(qū), BSD 調(diào)用. */
/* 用read()函數(shù)從套接字緩沖區(qū)中讀取遠(yuǎn)程客戶端發(fā)送的數(shù)據(jù),如果
數(shù)據(jù)長度為0則退出。*/
if (( cnt = read (new_sd, buf, sizeof(buf))) < 0 ) {
printf("network server %d ", pid);
printf("socket read failure &d\n", errno);
perror("network server");
close(new_sd);
exit(7);
}
else
if (cnt == 0) {
printf("network server received message");
printf(" of length %d\n", cnt);
printf("network server closing");
printf(" client connection...\n");
close (new_sd);
}
else {
/* 打印出接收到的信息,并發(fā)送回執(zhí) */
printf("network server %d received message",pid);
printf(" of length %d\n", cnt);
printf("network server %d received", pid);
printf(" the message %s\n", buf);
memset (buf,0,sizeof(buf)); /* 清空緩沖區(qū) */
/* bzero( buf, sizeof(buf)); * 清空緩沖區(qū), BSD 調(diào)用. */
strcpy(buf, "Message from server to client");
write (new_sd, buf, sizeof(buf));
} /* end of message-print else */
} /* end of do loop */
while (cnt != 0); /* 循環(huán)條件 */
exit(0); /* 子進(jìn)程結(jié)束 */
} /* End of if-child-process */
else /* 非子進(jìn)程,父進(jìn)程條件判斷 */
close (new_sd); /* 父進(jìn)程不需要此套接字 */
} /* end of while (1) */
} /* end of main procedure */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -