fgets和fputs函数
#include<stdio.h>
char *fgets(char *buf,int n,FILE *fp);
成功返回buf,失败或读取到文件末尾返回NULL
这个函数的作用便是在一个文件中读取一行,有三个参数第一个表示读取到数据存放的缓冲区,第二个参数为最大读取的个数,第三个表示文件标识符。
读取一行表示当读取到换行符时会在换行符的后面添加一个null,并返回,当没有读取到换行符但是已经读取到n-1一个字符时会在第n个位置添加一个null字符,表示字符串的结束。
根据fgets的特点来使用read函数来编写一个readline函数。
ssize_t readline(int fd,char * buf,size_t maxlen)
{
ssize_t n,rc;
char *ptr,c;
ptr=buf;
for(n=1;n<maxlen;++n)
{
again:
if((rc=read(fd,&c,1))==1)
{
*ptr++=c;
if(c=='\n')
break;
}
else if(rc==0)
{
*ptr=0;
return n-1;
}
else
{
if(errno==EINTR)
goto again;
return -1; //表示出错
}
}
*ptr=0;
return n;
}
函数成功返回读到的字节数,失败返回-1;
#include<stdio.h>
int fputs(char *buf,FILE *fp);
成功返回大于0的值,失败返回-1
这个函数是将buf缓冲区里的内容放入fp指向的文件里,这个函数时以null结束的,并不是判断换行符的。
feof和ferror函数
#include<stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
成功返回真,失败返回假
这两个函数的作用是判断一个FILE对象是否出现错误的,在FILE对象里存放有两个标志位,一个是文件结束标志,另一个是文件出错标志,常常使用这两个函数来判断文件是否出错。
进行改写一个fgets函数
char *Fgets(char *buf,int n,FILE *fp)
{
char *p;
if((p=fgets(buf,n,fp))==NULL)
{
if(feof(fp))
{
printf("fgets error\n");
return NULL;
} //表示出错
else
return NULL;
}
return p; //成功返回buf
}
分析:因为fgets到文件末尾和出错都会返回NULL,因此需要使用feof来判断是否出错。
下面是一个回射的程序
server
#include"unq.h"
#include"fun.h"
void str_echo(int fd);
int main()
{
int listenfd,newfd;
struct sockaddr_in addr;
addr.sin_port=htons(port);
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
listenfd=Socket(AF_INET,SOCK_STREAM,0);
Bind(listenfd,(struct sockaddr *)&addr,sizeof(addr));
Listen(listenfd,5);
while(1)
{
int pid;
newfd=Accept(listenfd,NULL,NULL);
if((pid=fork())<0)
{
printf("fork error\n");
return 0;
}
if(pid==0)
{
close(listenfd);
str_echo(newfd);
}
else
{
close(newfd);
}
}
}
这个服务器端和回射的操作是str_echo函数
str_echo函数
void str_echo(int fd)
{
char buf[max];
int n;
again:
while((n=read(fd,buf,max))>0)
{
write(fd,buf,n);
}
if(n<0&&errno==EINTR)
goto again;
else if(n<0)
{
printf("read error\n");
exit(0);
}
}
这个函数是将客户发过来的信息再发送给客户,write将read的返回值作为字符串的长度写入,当read返回为-1时可能是一个中断,因此做了一个判断,如果是一个中断则回到while继续执行。
下面是一个客户端的程序。
client
#include"unq.h"
#include"fun.h"
void str_cli(FILE *fp,int sockfd);
int main()
{
int fd;
struct sockaddr_in seraddr;
seraddr.sin_port=htons(port);
seraddr.sin_family=AF_INET;
seraddr.sin_addr.s_addr=inet_addr("127.0.0.1");
fd=Socket(AF_INET,SOCK_STREAM,0);
Connect(fd,(struct sockaddr *)&seraddr,sizeof(seraddr));
str_cli(fd,sockfd);
return 0;
}
其中str_cli函数是和服务器交互的程序。
str_cli
void str_cli(FILE *fp,int sockfd)
{
char *p;
char recvline[max],sendline[max];
while((p=Fgets(fp,sendline,max))!=NULL)
{
write(sockfd,sendline,strlen(sendline));
readline(sockfd,recvline,max);
Fputs(recvline,stdout);
}
}
成功返回
- 当客户端输入EOF时表示结束,fgets读取到文件结束返回NULL,则客户端程序结束,关闭套接字。
- 客户端向服务器端发送FIN,服务器read接收到EOF因此返回0,会结束服务器子进程,发送FIN对客户端,客户端对服务器进行响应,结束。