原文作者:aircraft
原文鏈接:https://www.cnblogs.com/DOMLX/p/9614820.html
一.標準I/O
1,什麼是標準I/O?其實是指C語言裏的文件操作函數,如:fopen,feof,fgetc,fputs等函數,他們和平臺無關。
2,網絡通信中使用標準I/O的優點:
- 良好的移植性。良好移植性這個不需多解釋,不僅是I/O函數,所有的標準函數都具有良好的移植性。因爲,爲了支持所有的操作系統(編譯器),這些函數都是按照ANSI C標準定義的。
- 標準I/O函數可以利用緩衝提高性能。在網絡通信中,read,write傳輸數據只有一種套接字緩衝,但使用標準I/O傳輸會有額外的緩衝,即I/O緩衝和套接字緩衝兩個。使用I/O緩衝主要是爲了提高性能,需要傳輸的數據越多時越明顯。因爲,一次發送更多的數據要比分多次發送同樣的數據性能要高。發送一次數據就對應一個數據包,往往數據包的頭信息比較大,它與數據大小無關。
3,網絡通信中使用標準I/O的缺點:
- 不容易進行雙向通信。
- 有時可能頻繁調用fflush函數。
- 需要以FILE結構體指針的形式返回文件描述符。
4,轉換函數
//將文件描述符轉換爲標準I/O函數中使用的FILE結構體指針 FILE * fdopen(int fildes, const char *mode); 成功時返回轉換的FILE結構體指針,失敗返回NULL //將FILE結構體指針轉換爲文件描述符 int fileno(FILE *stream); 成功返回轉換後的文件描述符,失敗返回-1
註釋:套接字中使用標準I/O,其實主要是運用在需要傳輸大量數據的情況,因爲其需要編寫額外代碼,所以並不像想象中的那麼常用。
先給個fdopen函數的簡單示例:
#include <stdio.h> main() { FILE * fp = fdopen(0, "w+"); fprintf(fp, "%s\n", "hello!"); fclose(fp); }
fileno示例:
#include <stdio.h> main() { FILE *fp; int fd; fp = fopen("/etc/passwd", "r"); fd = fileno(fp); printf("fd = %d\n", fd); fclose(fp); }
5.fgets與fputs函數:
1.fgets()
功能:有文件中讀取一字符串
定義:char *fgets(char *s, int size, FILE *stream) 說明: fgets()用來從參數stream所指的文件讀入字符並存到參數s所指向的內存空間,
直到讀到換行字符\n,讀到文件尾或是讀到size-1個字符爲止,最後會加入NULL作爲文件結束。
返回值: 成功 返回s的指針 失敗 返回NULL
2.fputs()
功能:將一指定的字符串寫入文件內
定義: char * fputs(const *char s, FILE *stream) 說明: fputs()用來將s所指的字符串寫到參數stream所指向的文件中 返回值: 成功 返回寫入字符串的個數 失敗 返回EOF
示例代碼:
include <stdio.h> int main() { int str[100]; fputs(fgets(str, 100, strin), strout); return 0; }
6.feof介紹:
1.在stdio.h中的宏定義
#define _IOEOF 0x0010 #define feof(_stream) ((_stream)->_flag & _IOEOF)
2.feof的使用:
feof用檢測流上的文件結束符,其返回值有兩種情況:如果遇到文件結束,函數值爲非零值,否則函數值爲0。
注:此處的文件結束標誌是EOF,EOF的16進制代碼爲0xFF(十進制爲-1),特用在文本文件中,因爲在文本文件中數據是以ASCⅡ代碼值的形式存放,普通字符的ASCⅡ代碼的範圍是32到127(十進制),與EOF不衝突,因此可以直接使用。但是在二進制文件中,數據有可能出現-1,因此不能用EOF來作爲二進制文件的結束標誌,可以通過feof函數來判斷。
注意了這些標準I/O函數速度是比平常的函數快很多很多的,不過也不是每次都用到,具體看對什麼情況了
二.基於標準I/O函數實現套接字服務端與客戶端通信
LINUX下服務端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void error_handling(char *message); int main(int argc, const char * argv[]) { int serv_sock, clnt_sock; char message[BUF_SIZE]; int str_len, i; struct sockaddr_in serv_adr, clnt_adr; socklen_t clnt_adr_sz; FILE *readfp; FILE *writefp; if(argc != 2) { printf("Usage: %s <port> \n", argv[0]); exit(1); } serv_sock = socket(PF_INET, SOCK_STREAM, 0); if(serv_sock == -1) error_handling("socket() error"); memset(&serv_adr, 0, sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); serv_adr.sin_port = htons(atoi(argv[1])); if(bind(serv_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1) error_handling("bind() error"); if(listen(serv_sock, 5) == -1) error_handling("listen() error"); clnt_adr_sz = sizeof(clnt_adr); for (i = 0; i < 5; i++) { clnt_sock = accept(serv_sock, (struct sockaddr *) &clnt_adr, &clnt_adr_sz); if(clnt_sock == -1) error_handling("accept() error"); else printf("Connected client %d \n", i+1); //將文件描述符轉換爲FILE結構體指針 readfp = fdopen(clnt_sock, "r"); writefp = fdopen(clnt_sock, "w"); while (!feof(readfp)) { //轉化爲標準I/O操作 fgets(message, BUF_SIZE, readfp);//相當於read,接收 fputs(message, writefp); //相當於write,發送 fflush(writefp); //刷新緩衝,立即顯示而不是一直放緩衝中,保證立即將數據傳輸到客服端 } fclose(readfp); fclose(writefp); } close(serv_sock); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(1); }
LINUX下客戶端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void error_handling(char *message); int main(int argc, const char * argv[]) { int sock; char message[BUF_SIZE]; int str_len; struct sockaddr_in serv_adr; FILE *readfp; FILE *writefp; if(argc != 3) { printf("Usage: %s <IP> <port> \n", argv[0]); exit(1); } sock = socket(PF_INET, SOCK_STREAM, 0); if(sock == -1) error_handling("socket() error"); memset(&serv_adr, 0, sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = inet_addr(argv[1]); serv_adr.sin_port = htons(atoi(argv[2])); if (connect(sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1) error_handling("connect() error"); else puts("Connected ..............."); readfp = fdopen(sock, "r"); writefp = fdopen(sock, "w"); while (1) { fputs("Input message(Q to quit): ", stdout); fgets(message, BUF_SIZE, stdin); if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) break; fputs(message, writefp); fflush(writefp); fgets(message, BUF_SIZE, readfp); printf("Message from server : %s", message); } fclose(writefp); fclose(readfp); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(1); }
最後說一句啦。本網絡編程入門系列博客是連載學習的,有興趣的可以看我博客其他篇。。。。
好了今天對網絡編程的學習就到這裏結束了,小飛機我要撤了去吃飯了。,,,很多人大學都很迷茫不知道學點什麼好,,,,,管他的,想那麼多幹嘛,先學了再說,對技術如有偏見,那麼你的領域就侷限於此了---《一專多精》
參考博客:https://blog.csdn.net/u010223072/article/details/48316117
參考博客:https://blog.csdn.net/qq_32103869/article/details/50834629
參考書籍:《TCP/IP 網絡編程 --尹聖雨》