一个简单的回射服务器的步骤:
1.客户端从标准输入读入一行文本,并写给服务器。
2.服务器端从网络输入读入这行文本,并返回给客户
3.客户端从网络输入读入这行反射文本,并显示在标准输出上。
如图:
服务器程序:
#include "unp.h" int main(int argc, char ** argv) { int listenfd,connfd; struct sockaddr_in cliaddr,servaddr; pid_t childpid; socklen_t clilen; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT);//#define SERV_PORT 9877 Bind(listenfd, (SA *)&servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for( ; ; ) { clilen = sizeof(cliaddr); connfd = Accept(listenfd, (SA *)&cliaddr, &clilen); if((childpid = Fork()) == 0) { Close(listenfd); str_echo(connfd); exit(0); } Close(connfd); } }
str_echo.c
#include "unp.h" void str_echo(int sockfd) { ssize_t n; char buf[MAXLINE];//#define MAXLINE 4096 again: while( (n = read(sockfd,buf,MAXLINE)) > 0) Writen(sockfd,buf,n); if(n<0 && errno == EINTR) goto again; else if (n<0) err_sys("str_echo:read error"); }
客户端程序:
#include "unp.h" #define DEST_IP "127.0.0.1" int main(int argc, char ** argv) { int sockfd; struct sockaddr_in servaddr; sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(struct sockaddr_in)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); Inet_pton(AF_INET, DEST_IP, &servaddr.sin_addr); Connect(sockfd, (SA *)&servaddr, sizeof(servaddr)); str_cli(stdin,sockfd); Close(sockfd); exit(0); }
//lib/str_cli.c
//lib/str_cli.c #include "unp.h" void str_cli(FILE *fp,int sockfd) { char sendline[MAXLINE],recvline[MAXLINE]; while(Fgets(sendline,MAXLINE,fp) != NULL) { Writen(sockfd,sendline,strlen(sendline)); if(Readline(sockfd,recvline,MAXLINE) == 0) err_quit("str_cli :server terminated prematually"); Fputs(recvline,stdout); } }
其中,writen,readline函数参见博客:
http://blog.csdn.net/kuzuozhou/article/details/7386666
fgets的用法:
fget函数的原型如下:char *fgets (char *buf, int n, FILE *fp)
功能:从文件流读取一行,送到缓冲区,使用时注意以下几点:
1.当遇到换行符或者缓冲区已满,fgets就会停止,返回读到的数据,
注意的是不能用fgets读二进制文件,因为fgets会把二进制文件当成文本文件来处理,这势必会产生乱码。
2.每次调用,fgets都会把缓冲区的最后一个字符设为 \0,这意味着最后一个字符不能用来存放需要的数据,
所以如果有一行,含有 LINE_SIZE 个字符(包括换行符),要想把这行读入缓冲区,请把参数 n 设为 LINE_SIZE+1
多留一个位置存储 \0
3. 由结论1可推出:给定参数n,fgets只能读取n-1个字符(包括换行符),如果有一行超过n-1个字符,
那么fgets返回一个不完整的行,也就是说,只读取该行的前n-1个字符,但是,缓冲区总是以 \0 字符结尾,
对fgets的下一次调用会继续读该行。
代码:
FILE* fp = fopen(argv[1], "r"); char buf[200]; while(fgets(buf, 200, fp) != NULL) { /* 每行的字符不能超过199(包括换行符)才能正常工作 */ printf("%s",buf); }