echo服务器(回显服务器)
轉(zhuǎn)載:https://blog.csdn.net/lanyan822/article/details/7679733
寫在文章前:
? ? ? ??這學(xué)習(xí)linux編程,也有一段時間了。雖然是一個人看書,琢磨。也想把自己看過的做一個總結(jié),一步一步來,總有一天會質(zhì)變的。不得不說,linux太博大精深了,里面需要學(xué)的東西太多了。
?
? ?echo服務(wù)器,可以看成 學(xué)習(xí)網(wǎng)絡(luò)編程的“hello world”。
? ?echo服務(wù)器,描述起來很簡單,服務(wù)端收到什么,就給客戶端發(fā)送什么。也就是這個簡單的程序,能夠讓你從中學(xué)到不少東西。多線程,多進(jìn)程,I/O復(fù)用,信號處理這些都會遇到。
? ?第一個echo服務(wù)程序,不需要考慮各種問題,只要能夠完成功能就行。
? ?先來看看簡易流程圖
? ?
基于TCP Socket編程的流程圖類似,服務(wù)端主要是,創(chuàng)建socket、綁定IP和端口、監(jiān)聽、接受連接、處理數(shù)據(jù)包、關(guān)閉連接。客戶端則主要是,創(chuàng)建socket、連接到服務(wù)器、發(fā)送請求、關(guān)閉連接。
?
? echo服務(wù)端代碼:
/* * File: Server.c* Author: root** Created on 2012年6月20日, 下午1:29*/#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h>#define SERVERIP "192.168.0.23" #define SERVERPORT 12345 #define MAXBUFFER 256int main(int argc, char** argv) {int serverFd, connfd,ret;socklen_t len;struct sockaddr_in serveraddr,clientaddr;char readBuf[MAXBUFFER]={0};char ip[40]={0};serverFd=socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建socketif(serverFd < 0){printf("socket error:%s\n",strerror(errno));exit(-1);}bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family=AF_INET;serveraddr.sin_port=htons(SERVERPORT);inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr);//將c語言字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序ret=bind(serverFd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//綁定IP和端口if(ret!=0){close(serverFd);printf("bind error:%s\n",strerror(errno));exit(-1);}ret=listen(serverFd,5);//監(jiān)聽if(ret!=0){close(serverFd);printf("listen error:%s\n",strerror(errno));exit(-1);}len=sizeof(clientaddr);bzero(&clientaddr,sizeof(clientaddr));while (1){connfd = accept(serverFd, (struct sockaddr *) &clientaddr, &len);//接受客戶端的連接printf("%s 連接到服務(wù)器 \n",inet_ntop(AF_INET,&clientaddr.sin_addr,ip,sizeof(ip)));if (serverFd < 0){printf("accept error : %s\n", strerror(errno));continue;}while((ret=read(connfd,readBuf,MAXBUFFER)))//讀客戶端發(fā)送的數(shù)據(jù){write(connfd,readBuf,MAXBUFFER);//寫回客戶端bzero(readBuf,MAXBUFFER);}if(ret==0){printf("客戶端關(guān)閉連接\n"); }else{printf("read error:%s\n",strerror(errno));}close(connfd);}close(serverFd);return 0; }? ?echo 客戶端代碼
/* * File: Client.c* Author: root** Created on 2012年6月20日, 下午1:30*/#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h>#define SERVERIP "192.168.0.23" #define SERVERPORT 12345 #define MAXBUFFER 256int main(int argc, char** argv) { int clientFd,ret;struct sockaddr_in serveraddr;char buf[MAXBUFFER];clientFd=socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建socketif(clientFd < 0){printf("socket error:%s\n",strerror(errno));exit(-1);}bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family=AF_INET;serveraddr.sin_port=htons(SERVERPORT);inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr);ret=connect(clientFd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//連接到服務(wù)器if(ret!=0){close(clientFd);printf("connect error:%s\n",strerror(errno));exit(-1);}while(1){bzero(buf,sizeof(buf));scanf("%s",buf);write(clientFd,buf,sizeof(buf));//寫數(shù)據(jù)bzero(buf,sizeof(buf));read(clientFd,buf,sizeof(buf));//讀數(shù)據(jù)printf("echo:%s\n",buf);}close(clientFd);return (EXIT_SUCCESS); }執(zhí)行效果圖:
?
?
在這里需要注意一個問題:網(wǎng)絡(luò)字節(jié)序問題
內(nèi)存中存儲字節(jié)有兩種方式,一種是小端字節(jié)序(低序字節(jié)儲存在起始地址),第二種是大端字節(jié)序(高位字節(jié)存儲在起始地址)。而且這兩種字節(jié)序都有在使用。當(dāng)兩臺機(jī)器通信時,為了避免字節(jié)序之間轉(zhuǎn)換問題,系統(tǒng)提供了4個函數(shù)
#include<netinet/in.h> uint32_t ntohl (uint32_t __netlong) ; uint16_t ntohs (uint16_t __netshort); uint32_t htonl (uint32_t __hostlong); uint16_t htons (uint16_t __hostshort);用這個程序說明一下,ctrl-z,ctrl-c,ctrl-d的差別
ctrl-c 發(fā)送 SIGINT 信號給前臺進(jìn)程組中的所有進(jìn)程。常用于終止正在運(yùn)行的程序。
? ? ?從上面那個圖可以看出,ctrl+c終止客戶端程序
ctrl-z 發(fā)送 SIGTSTP 信號給前臺進(jìn)程組中的所有進(jìn)程,常用于掛起一個進(jìn)程。
? ? ctrl+z,將程序掛起。fg命令重新啟動前臺被中斷的任務(wù),bg命令把被中斷的任務(wù)放在后臺執(zhí)行.
ctrl-d 不是發(fā)送信號,而是表示一個特殊的二進(jìn)制值,表示 EOF。
程序不足之處:
?
總結(jié)
以上是生活随笔為你收集整理的echo服务器(回显服务器)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解阻塞socket和非阻塞sock
- 下一篇: C++是类型安全的吗?