創(chuàng)建套接口 在這一部分,,我們將會(huì)看到創(chuàng)建套接口與創(chuàng)建管道一樣的容易,。雖然有一些我們將會(huì)了解到的函數(shù)參數(shù),。為了能創(chuàng)建成功,,這些參數(shù)必須提供合適的值。 socketpair函數(shù)概要如下: #include <sys/types.h> #include <sys/socket.h> int socketpair(int domain, int type, int protocol, int sv[2]); sys/types.h文件需要用來(lái)定義一些C宏常量,。sys/socket.h文件必須包含進(jìn)來(lái)定義socketpair函數(shù)原型,。 socketpair函數(shù)需要四個(gè)參數(shù)。他們是: 套接口的域 套接口類型 使用的協(xié)議 指向存儲(chǔ)文件描述符的指針 domain參數(shù)直到第2單我們才會(huì)解釋,。對(duì)于socketpair函數(shù)而言,,只需提供C宏AF_LOCAL。 類型參數(shù)聲明了我們希望創(chuàng)建哪種類型的套接口,。socketpair函數(shù)的選擇如下: SOCK_STREAM SOCK_DGRAM 套接口類型的選擇我們將會(huì)在第4章談到,。在這一章中,我們只需要簡(jiǎn)單的使用SOCK_STREAM套接口類型,。 對(duì)于socketpair函數(shù),,protocol參數(shù)必須提供為0。 參數(shù)sv[2]是接收代表兩個(gè)套接口的整數(shù)數(shù)組,。每一個(gè)文件描述符代表一個(gè)套接口,,并且與另一個(gè)并沒(méi)有區(qū)別。 如果函數(shù)成功,,將會(huì)返回0值,。否則將會(huì)返回-1表明創(chuàng)建失敗,并且errno來(lái)表明特定的錯(cuò)誤號(hào),。 使用socketpair的例子 為了演示如何使用socketpair函數(shù),,我們用下面的例子來(lái)進(jìn)行演示。 1: /* Listing 1.1: 2: * 3: * Example of socketpair(2) function: 4: */ 5: #include <stdio.h> 6: #include <stdlib.h> 7: #include <unistd.h> 8: #include <errno.h> 9: #include <string.h> 10: #include <sys/types.h> 11: #include <sys/socket.h> 12: 13: int 14: main(int argc,char **argv) { 15: int z; /* Status return code */ 16: int s[2]; /* Pair of sockets */ 17: 18: /* 19: * Create a pair of local sockets: 20: */ 21: z = socketpair(AF_LOCAL,SOCK_STREAM,0,s); 22: 23: if ( z == -1 ) { 24: fprintf(stderr, 25: "%s: socketpair(AF_LOCAL,SOCK_STREAM,0)\n", 26: strerror(errno)); 27: return 1; /* Failed */ 28: } 29: 30: /* 31: * Report the socket file descriptors returned: 32: */ 33: printf("s[0] = %d;\n",s[0]); 34: printf("s[1] = %d;\n",s[1]); 35: 36: system("netstat --unix -p"); 37: 38: return 0; 39: } 演示程序的描述如下: 1 在第16行聲明數(shù)組s[2]用來(lái)存儲(chǔ)用來(lái)引用兩個(gè)新創(chuàng)建的套接口的文件描述符,。 2 在第21行調(diào)用socketpair函數(shù),。domain參數(shù)指定為AF_LOCAL,套接口類型參數(shù)指定為SOCK_STREAM,,而協(xié)議指定為0,。 3 23行的if語(yǔ)句用來(lái)測(cè)試socketpair函數(shù)是否成功。如果z的值為-1,就會(huì)向標(biāo)準(zhǔn)錯(cuò)誤發(fā)送報(bào)告,,并且在27行退出程序,。 4 如果函數(shù)調(diào)用成功,,控制語(yǔ)句就會(huì)轉(zhuǎn)到33,并且在34行向標(biāo)準(zhǔn)輸出報(bào)告返回的文件單元數(shù)。 5 36行使用system函數(shù)來(lái)調(diào)用netstat命令,。命令選項(xiàng)--unix表明只報(bào)告Unix套接口,,-p選項(xiàng)則是要報(bào)告進(jìn)程信息。 使用提供的Makefile,,我們可以用make命令來(lái)編譯這個(gè)程序: $ make 01lst01 gcc -c -D_GNU_SOURCE -Wall 01LST01.c gcc 01LST01.o -o 01lst01 為了執(zhí)行這個(gè)演示程序,,我們可以執(zhí)行下面的命令: $ ./01lst01 程序的執(zhí)行結(jié)果如下: 1: $ ./01lst01 2: s[0] = 3; 3: s[1] = 4; 4: (Not all processes could be identified, non-owned process info 5: will not be shown, you would have to be root to see it all.) 6: Active UNIX domain sockets (w/o servers) 7: Proto RefCnt Flags Type . . . I-Node PID/Program name Path 8: unix 1 [] STREAM . . . 406 - @00000019 9: unix 1 [] STREAM . . . 490 - @0000001f 10: unix 1 [] STREAM . . . 518 - @00000020 11: unix 0 [] STREAM . . . 117 - @00000011 12: unix 1 [] STREAM . . . 789 - @00000030 13: unix 1 [] STREAM . . . 549 - @00000023 14: unix 1 [] STREAM . . .1032 662/01lst01 15: unix 1 [] STREAM . . .1031 662/01lst01 16: unix 1 [] STREAM . . . 793 - /dev/log 17: unix 1 [] STREAM . . . 582 - /dev/log 18: unix 1 [] STREAM . . . 574 - /dev/log 19: unix 1 [] STREAM . . . 572 - /dev/log 20: unix 1 [] STREAM . . . 408 - /dev/log 21: $ 在我們上面的輸入顯示中,在第1行調(diào)用可執(zhí)行程序01LST01,。第2行和第3行顯示了我們?cè)谖募枋龇?和4上打開(kāi)套接口,。接下來(lái)的4到20行是程序中netstat命令的輸出。 盡管這個(gè)程序并沒(méi)有使用創(chuàng)建的套接口來(lái)做任何事情,,但是他確實(shí)演示了套接口的創(chuàng)建,。并且他演示了套接口單元數(shù)的分配與打開(kāi)的文件的方式一樣。 在套接口上執(zhí)行I/O操作 我們?cè)谇懊嬉呀?jīng)了解到套接口可以像任何打開(kāi)的文件一樣向其中寫(xiě)入或是從中讀取,。在這一部分將我們將會(huì)親自演示這一功能,。然而為了試都討論的完整,我們先來(lái)看一下read,,write,close的函數(shù)概要: #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd); 這些應(yīng)是我們已經(jīng)熟悉的Linux的輸入/輸入函數(shù),。通過(guò)回顧我們可以看到,read函數(shù)返從文件描述符fd中返回最大count字節(jié)的輸入,,存放到buf緩沖區(qū)中,。返回值代表實(shí)際讀取的字節(jié)數(shù),。如果返回0則代表文件結(jié)束,。 write函數(shù)將我們指定的buf緩沖區(qū)中總計(jì)count的字節(jié)寫(xiě)入文件描述符fd中。返回值代表實(shí)際寫(xiě)入的字節(jié)數(shù),。通常這必須與指定的count參數(shù)相匹配,。然而也會(huì)有一些情況,這個(gè)值要count小,,但是我們沒(méi)有必要擔(dān)心這樣的情況,。 最后,如果文件成功關(guān)閉close就會(huì)返回0,。對(duì)于這些函數(shù),,如果返回-1則表明有錯(cuò)誤發(fā)生,并且錯(cuò)誤原因?qū)?huì)發(fā)送到外部變量errno中,。為了可以訪問(wèn)這個(gè)變量,,我們需要在源文件中包含errno.h頭文件。 下面的例子是在套接口的兩個(gè)方向上執(zhí)行讀取與寫(xiě)入操作,。 /***************************************** * * Listing 1.2 * * Example performing I/O on s socket pair: * * ******************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> int main(int argc,char **argv) { int z; /* Status return code */ int s[2]; /* Pair of sockets */ char *cp; /* A work pointer */ char buf[80]; /* work buffer */ /* * Create a pair of local sockets: */ z = socketpair(AF_LOCAL,SOCK_STREAM,0,s); if(z == -1) { fprintf(stderr, "%s:socketpair(AF_LOCAL,SOCK_STREAM,""0)\n",strerror(errno)); return 1; /* Failed */ } /* * Write a message to socket s[1]: */ z = write(s[1],cp="Hello?",6); if(z<0) { fprintf(stderr,"%s:wirte(%d,\"%s\",%d)\n",strerror(errno),s[1],cp,strlen(cp)); return 2; /* Failed */ } printf("Wrote message '%s' on s[1]\n",cp); /* * Read from socket s[0]: */ z = read(s[0],buf,sizeof buf); if(z < 0) { fprintf(stderr,"%s:read(%d,buf,%d)\n", strerror(errno),s[0],sizeof buf); return 3; /* Failed */ } /* * Report received message: */ buf[z] = 0; /* NUL terminate */ printf("Recevie message '%s' from socket s[0]\n",buf); /* * Send a reply back to s[1] from s[0]: */ z = write(s[0],cp="Go away!",8); if(z < 0) { fprintf(stderr,"%s:write(%d,\"%s\",%d)\n", strerror(errno),s[0],cp,strlen(cp)); return 4; /* Failed */ } printf("Wrote message '%s' on s[0]\n",cp); /* * Read from socket s[1]: */ z = read(s[1],buf,sizeof buf); if(z < 0) { fprintf(stderr,"%s:read(%d,buf,%d)\n", strerror(errno),s[1],sizeof buf); return 3; /* Failed */ } /* * Report message recevied by s[0]: */ buf[z] = 0; /*NUL terminate */ printf("Received message '%s' from socket s[1]\n", buf); /* * Close the sockets: */ close(s[0]); close(s[1]); puts("Done"); return 0; } 程序調(diào)用的步驟總結(jié)如下: 1 在第23行調(diào)用socketpair函數(shù),,如果成功返回,,則將生成的套接口存放在數(shù)組s中。 2 在第25行測(cè)試函數(shù)是否成功,,如果發(fā)生錯(cuò)誤,,將會(huì)報(bào)告錯(cuò)誤。 3 在第36行一個(gè)由6個(gè)字符組成的消息"Hello?"寫(xiě)入套接口s[1],。注意并沒(méi)有寫(xiě)入空字節(jié),,因?yàn)樵趙rite函數(shù)的count參數(shù)中僅指定了6個(gè)字節(jié)。 4 第37到第42行檢測(cè)并報(bào)告可能發(fā)生的錯(cuò)誤,。 5 第44行聲明一個(gè)成功寫(xiě)操作,。 6 在第49行read調(diào)用試著從另一個(gè)套接口s[0]讀取消息。在這條語(yǔ)句中,,可以讀取任何最大為buf[]數(shù)組尺寸的消息,。 7 第50行到第55行檢測(cè)并服務(wù)在read語(yǔ)句中可能發(fā)生的錯(cuò)誤。 8 第60行到第62行報(bào)告一條成功接收的消息,。 9 第67行到第73行向套接口s[0]寫(xiě)入一條回復(fù)消息"Go away!",。這就演示了不同于管道,信息在可以作為端點(diǎn)的套接口中雙向傳送,。 10 第75行聲明一個(gè)成功的寫(xiě)操作,。 11 第80行到第86行應(yīng)從通信線路的另一個(gè)端點(diǎn)套接口s[1]中讀取信息"Go away!"。 12 第91行到第93行報(bào)告成功接收的信息,。 13 這兩個(gè)套接口在第98行和第99行關(guān)閉,。 14 在第102行程序退出。 當(dāng)程序被調(diào)用時(shí),,輸出結(jié)果如下: $ ./01lst02 Wrote message 'Hello?' on s[1] Received message 'Hello?' from socket s[0] Wrote message 'Go away!' on s[0] Received message 'Go away!' from socket s[1] Done. $ 如果我們跟蹤我們?cè)谇懊嫠串?huà)的步驟,,我們就會(huì)發(fā)現(xiàn)信息是在套接口中雙向傳送的。而且我們演示了套接口用與文件相同的方式來(lái)關(guān)閉,。 關(guān)閉套接口 在前面,,我們看到如何來(lái)創(chuàng)建一對(duì)套接口,并且看到如何使用這些套接口來(lái)執(zhí)行最基本的輸入與輸出操作,。我們也可以看到套接口可以使用與通過(guò)調(diào)用close函數(shù)來(lái)關(guān)閉文件的方式來(lái)關(guān)閉?,F(xiàn)在我們來(lái)了解一下關(guān)閉套接口所提供的函數(shù)。 當(dāng)從通過(guò)pipe函數(shù)創(chuàng)建的管道中讀取時(shí),,當(dāng)接收到一個(gè)文件結(jié)尾時(shí),,接收就會(huì)認(rèn)為不會(huì)再有要接收的數(shù)據(jù)。當(dāng)關(guān)閉管道的寫(xiě)端時(shí),,文件結(jié)束的條件是通過(guò)寫(xiě)進(jìn)程發(fā)送的,。 同樣的過(guò)程也可以用在套接口上。當(dāng)另一個(gè)端點(diǎn)關(guān)閉時(shí),接收端就會(huì)收到一個(gè)文件結(jié)束的標(biāo)識(shí),。 當(dāng)本地進(jìn)程希望通知遠(yuǎn)程端不再接收數(shù)據(jù)時(shí)就會(huì)出現(xiàn)問(wèn)題,。如果本地進(jìn)程關(guān)閉了他的套接口,這是可以適用的,。然而,,如果他希望從遠(yuǎn)程端接收一個(gè)確認(rèn)信息,這是不可能的,,因?yàn)楝F(xiàn)在他的套接口已經(jīng)關(guān)閉了,。這樣的情況需要一個(gè)半關(guān)閉套接口的方法。 shutdown函數(shù) 下面顯示了shutdown函數(shù)的概要: #include <sys/socket.h> int shutdown(int s, int how); shutdown函數(shù)需要兩個(gè)參數(shù),。他們是: 套接口描述符s指定了要部分關(guān)閉的套接口,。 參數(shù)how指定要如何關(guān)閉這個(gè)套接口中。 如果函數(shù)成功則返回0,。如果調(diào)用失敗則會(huì)返回-1,錯(cuò)誤原因?qū)?huì)發(fā)送到errno,。 how的可能值如下: 值 宏 描述 0 SHUT_RD 在指定的套接口上不再允許讀操作。 1 SHUT_WR 在指定的套接口上不再允許寫(xiě)操作,。 2 SHUT_RDWR 在指定的套接口上不再允許讀寫(xiě)操作,。 注意當(dāng)how值指定為2時(shí),這個(gè)函數(shù)的調(diào)用與close函數(shù)調(diào)用相同,。 關(guān)閉向一個(gè)套接口的寫(xiě) 下面的代碼演示了如何指定在本地的套接口上不再執(zhí)行寫(xiě)操作: int z; int s; /* Socket */ z = shutdown(s, SHUT_WR); if ( z == -1 ) perror("shutdown()"); 關(guān)閉套接口的寫(xiě)端解決了一系列難題,。他們是: 清空包含任何要發(fā)送的數(shù)據(jù)的內(nèi)核緩沖區(qū)。通過(guò)內(nèi)核網(wǎng)絡(luò)軟件來(lái)緩沖數(shù)據(jù)來(lái)改進(jìn)性能,。 向遠(yuǎn)程套接口發(fā)送文件結(jié)束標(biāo)識(shí),。這就通知遠(yuǎn)程讀進(jìn)程在這個(gè)套接口上不會(huì)再向他發(fā)送數(shù)據(jù)。 保留半關(guān)閉套接口為讀打開(kāi),。這就使得在套接口上發(fā)送了文件結(jié)束標(biāo)識(shí)以后還可以接收確認(rèn)信息,。 丟棄在這個(gè)套接口上的打開(kāi)引用計(jì)數(shù)。只有最后在這個(gè)套接口上的close函數(shù)將會(huì)發(fā)送一個(gè)文件結(jié)束標(biāo)識(shí),。 處理復(fù)制的套接口 如果一個(gè)套接口文件描述符通過(guò)dup或者是dup2函數(shù)來(lái)調(diào)用進(jìn)行復(fù)制,,只有最后的close函數(shù)調(diào)用可以關(guān)閉這個(gè)套接口,。這是因?yàn)榱硗鈴?fù)制的文件描述符仍處于使用狀態(tài),。如下面的代碼如演示的樣子: int s; /* Existing socket */ int d; /* Duplicated socket */ d = dup(s); /* duplicate this socket */ close(s); /* nothing happens yet */ close(d); /* last close, so shutdown socket */ 在這個(gè)例子中,第一個(gè)close函數(shù)調(diào)用不會(huì)有任何效果,。先關(guān)閉其中的任何一個(gè)都是一樣的結(jié)果,。關(guān)閉s或者d將會(huì)為同一個(gè)套接口保留一個(gè)文件描述符。只有通過(guò)close函數(shù)調(diào)用來(lái)關(guān)閉最后一個(gè)存在的文件描述符才會(huì)有效果,。在這個(gè)例子中,,關(guān)閉d文件描述符關(guān)閉了這個(gè)套接口。 shutdown函數(shù)避免了這種區(qū)別。重復(fù)這個(gè)例子代碼,,通過(guò)使用shutdown函數(shù)解決了這個(gè)問(wèn)題: int s; /* Existing socket */ int d; /* Duplicated socket */ d = dup(s); /* duplicate this socket */ shutdown(s,SHUT_RDWR); /* immediate shutdown */ 盡管套接口s也在文件單元d上打開(kāi),,shutdown函數(shù)立刻使得套接口執(zhí)行關(guān)閉操作。這個(gè)操作在打開(kāi)的文件描述符s和d都是同樣的效果,,因?yàn)樗麄冎赶蛲粋€(gè)套接口,。 這個(gè)問(wèn)題出現(xiàn)的另一個(gè)方式就是執(zhí)行了fork函數(shù)調(diào)用。任何優(yōu)先級(jí)高于fork操作的套接口都會(huì)在子進(jìn)程中被復(fù)制,。 關(guān)閉從一個(gè)套接口讀 關(guān)閉套接口的讀取端將會(huì)使得待讀取的任何數(shù)據(jù)都會(huì)被忽略掉,。如果從遠(yuǎn)程套接口發(fā)送來(lái)更多的數(shù)據(jù),也同樣會(huì)被忽略掉,。然而任何試著從這個(gè)套接口進(jìn)行讀取的進(jìn)程都會(huì)返回一個(gè)錯(cuò)誤,。這通常用來(lái)強(qiáng)制協(xié)議或是調(diào)試代碼。 shutdown函數(shù)的錯(cuò)誤代碼如下: 錯(cuò)誤 描述 EBADF 指定的套接口不是一個(gè)可用的文件描述符 ENOTSOCK 指定的文件描述符不是一個(gè)套接口 ENOTCONN 指定的套接口并沒(méi)有連接 從這個(gè)表中我們可以看到,,對(duì)于已連接的套接口應(yīng)只調(diào)用shutdown函數(shù),,否則就會(huì)返回ENOTCONN錯(cuò)誤代碼。 編寫(xiě)一個(gè)客戶/服務(wù)器例子 現(xiàn)在我們所了解的套接口API的集合已經(jīng)足夠讓我們開(kāi)始一些有趣的嘗試了,。在這一部分,,我們會(huì)檢測(cè),編譯并且測(cè)試一個(gè)簡(jiǎn)單的通過(guò)套接口進(jìn)行通信的客戶與服務(wù)器進(jìn)程,。 為了使得這個(gè)程序盡可能的小,,將會(huì)啟動(dòng)一個(gè)程序,然后復(fù)制為一個(gè)客戶進(jìn)程與一個(gè)服務(wù)器進(jìn)程,。子進(jìn)程將會(huì)是客戶端程序角色,,而原始的父進(jìn)程將會(huì)執(zhí)行服務(wù)器的角色。下圖顯示了父進(jìn)程與子進(jìn)程的關(guān)系以及套接口的使用,。 父進(jìn)程是最初啟動(dòng)的程序,。他立刻通過(guò)調(diào)用socketpair函數(shù)來(lái)生成一對(duì)套接口,然后通過(guò)調(diào)用fork函數(shù)將自己復(fù)制為兩個(gè)進(jìn)程,。 服務(wù)器將會(huì)接收請(qǐng)求,,執(zhí)行請(qǐng)求,然后退出,。類似的客戶端將會(huì)執(zhí)行請(qǐng)求,,報(bào)告服務(wù)器響應(yīng),然后退出,。 請(qǐng) 求將會(huì)采用strftime函數(shù)的第三個(gè)參數(shù)的格式,。這是一個(gè)用來(lái)格式化日期與時(shí)間字符串的格式字符串。服務(wù)器將會(huì)在接收到請(qǐng)求時(shí)得到當(dāng)前的日期與時(shí)間,。 服務(wù)器將會(huì)使用客戶端的請(qǐng)求字符串來(lái)將其格式化為最終的字符串,,然后發(fā)送給客戶端。我們先來(lái)回顧一個(gè)strftime函數(shù)的概要: #include <time.h> size_t strftime(char *buf, size_t max, const char *format, const struct tm *tm); 參數(shù)buf與max分別指定了輸出緩沖區(qū)以及最大長(zhǎng)度。參數(shù)format是一個(gè)輸入字符串,,可以允許我們來(lái)格式化日期與時(shí)間字符串,。最后參數(shù)tm用來(lái)指定必須來(lái)創(chuàng)建輸出日期與時(shí)間字符串的日期與時(shí)間組件。 /***************************************** * * Listing 1.3 * * Client/Server Example Using socketpair * and fork: * * ******************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <time.h> /* * As of RedHat 6.0,these are still not defined: */ #ifndef SHUT_WR #define SHUT_RD 0 #define SHUT_WR 1 #define SHUT_RDWR 2 #endif /* * Main program */ int main(int argc,char **argv) { int z; /* Status return code */ int s[2]; /* Pair of sockets */ char *msgp; /* A message pointer */ int mlen; /* Message length */ char buf[80]; /* work buffer */ pid_t chpid; /* Child PID */ /* * Create a pair of local sockets: */ z = socketpair(AF_LOCAL,SOCK_STREAM,0,s); if(z == -1) { fprintf(stderr,"%s:socketpair(2)\n",strerror(errno)); exit(1); } /* * Now fork() into two processes: */ if((chpid = fork()) == (pid_t)-1) { /* * Failed to fork into two processes: */ fprintf(stderr,"%s:fork(2)\n",strerror(errno)); exit(1); } else if(chpid == 0) { /* * This is child process(client) */ char rxbuf[80]; /*Receive buffer*/ printf ("Parent PID is %ld\n",(long)getppid()); close(s[0]); /* Server uses s[1] */ s[0] = -1; /*Forget this unit */ /* * Form the message and its length: */ msgp = "%A %d-%b-%Y %l:%M %p"; mlen = strlen(msgp); printf("Child sending request '%s'\n",msgp); fflush(stdout); /* * Write a request to the server: */ z = write(s[1],msgp,mlen); if(z<0) { fprintf(stderr,"%s:write(2)\n",strerror(errno)); exit(1); } /* * Now indicate that we will not be writing * anything further to our socket,by shutting * down the write side of the socket: */ if(shutdown(s[1],SHUT_WR) == -1) { fprintf(stderr,"%s:shutdown(2)\n",strerror(errno)); exit(1); } /* * Recevie the reply from the server: */ z = read(s[1],rxbuf,sizeof rxbuf); if(z<0) { fprintf(stderr,"%s:read(2)\n",strerror(errno)); exit(1); } /* * Put a null byte at the end of what we * received from the server: */ rxbuf[z]=0; /* * Report the result: */ printf("Server returned '%s'\n",rxbuf); fflush(stdout); close(s[1]); /*Close our end now*/ } else { /* * This is parent process(server): */ int status; /*Child termintation status*/ char txbuf[80]; /*Reply buffer*/ time_t td; /*Current date&time*/ printf("Child PID is %ld\n",(long)chpid); fflush(stdout); close(s[1]); /* Cient uses s[0] */ s[1] = -1; /* Forget this desciptor */ /* * Wait for a request from the client: */ z = read(s[0],buf,sizeof buf); if(z<0) { fprintf(stderr,"%s:read(2)\n",strerror(errno)); exit(1); } /* * Put a null byte at the end of the * message we recevied from the client: */ buf[z] = 0; /* * Now perform the server function on * the received message */ time(&td); /* Get current time */ strftime(txbuf,sizeof txbuf, /* Buffer */ buf, /* Input fromate*/ localtime(&td));/* Input time */ /* * Send back the response to client: */ z = write (s[0],txbuf,strlen(txbuf)); if(z<0) { fprintf(stderr,"%s:write(2)\n",strerror(errno)); exit(1); } /* * Close our end of the socket */ close(s[0]); /* * Wait for the child process to exit: */ waitpid(chpid,&status,0); } return 0; } |
|