一个简单的回射服务器的步骤:
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.youkuaiyun.com/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);
}