本节介绍:单进程迭代服务器和停等模式的单进程客户程序
单进程迭代服务器:它的缺点是在当前客户被处理完之前,新到达的客户无法被服务;
停等模式客户程序:缺点,当它等待用户输入而阻塞时,无法监视网络事件,二是停等模式批处理效率极低
该模式现实很少使用,效率极低,模型简单,一般学习网络编程都是从该模式开始学习,下面是这个模式的一个例子,客户端输入一段内容,服务器接收后不做任何处理,直接原内容返回。
如下是客户端程序(编译时要加上readline.c文件):
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdio.h>
#include<errno.h>
#include<time.h>
#include<netinet/in.h>
#define MAXLINE 4096
#define PORT 9877
/*Write n bytes to fd*/
ssize_t writen(int fd, const void *vptr,size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while(nleft > 0)
{
if((nwritten = write(fd,ptr,nleft)) < 0)
{
if(errno == EINTR)
{
continue;
}else if(nleft == n)
{
return -1;
}else
{
break;
}
}else if(nwritten == 0)
{
break;
}else
{
nleft -= nwritten;
ptr += nwritten;
}
}
return n-nleft;
}
void str_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE],recvline[MAXLINE];
while(1)
{
if(fgets(sendline,MAXLINE,fp) == NULL)
{
if(ferror(fp))
{
perror("fgets error");
exit(1);
}else
{
break; //EOF
}
}
if(writen(sockfd,sendline,strlen(sendline)) == -1)
{
perror("write error");
exit(1);
}
if(Readline(sockfd,recvline,MAXLINE) == 0)//EOF
{
perror("server terminated permaturely");
}
if(fputs(recvline,stdout) == EOF)
{
perror("fputs error");
exit(1);
}
}
}
int main(int argc, char **argv)
{
if(argc != 2)
{
perror("usage: a.out <IPaddress>");
exit(1);
}
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket() failed");
exit(1);
}
struct sockaddr_in seraddr;
memset(&seraddr,0,sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(PORT);
if(inet_pton(AF_INET,argv[1],&seraddr.sin_addr) <= 0)
{
perror("inet_pton() failed");
exit(1);
}
if(connect(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr)) == -1)
{
perror("connect() failed");
exit(1);
}
str_cli(stdin,sockfd);
return 0;
}
如下是服务器程序:
include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdio.h>
#include<errno.h>
#include<time.h>
#include<netinet/in.h>
#define MAXLINE 4096
#define PORT 9877
#define LISTENQ 1024
/*Write n bytes to fd*/
ssize_t writen(int fd, const void *vptr,size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while(nleft > 0)
{
if((nwritten = write(fd,ptr,nleft)) < 0)
{
if(errno == EINTR)
{
continue;
}else if(nleft == n)
{
return -1;
}else
{
break;
}
}else if(nwritten == 0)
{
break;
}else
{
nleft -= nwritten;
ptr += nwritten;
}
}
return n-nleft;
}
/*read fd and echo back*/
void str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE+1];
while(1)
{
if((n = read(sockfd,buf,MAXLINE)) > 0)
{
if(n = writen(sockfd,buf,n) == -1)
{
perror("write sockfd error");
exit(1);
}
}else if(n == 0)
{
break;
}else
{
if(errno == EINTR)
{
continue;
}
perror("read error");
exit(1);
}
}
}
int main(int argc, char **argv)
{
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1)
{
perror("socket() failed");
exit(1);
}
struct sockaddr_in seraddr;
memset(&seraddr,0,sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
seraddr.sin_port = htons(PORT);
if(bind(listenfd,(struct sockaddr *)&seraddr,sizeof(seraddr)) == -1)
{
perror("bind() failed");
exit(1);
}
if(listen(listenfd,LISTENQ) == -1)
{
perror("listen() failed");
exit(1);
}
int connfd;
char buff[MAXLINE];
struct sockaddr_in cliaddr;
socklen_t clilen;
for(;;)
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
if(connfd == -1)
{
perror("accept() failed");
exit(1);
}
str_echo(connfd);
if(close(connfd) == -1)
{
perror("close() failed");
exit(1);
}
}
return 0;
}
编译服务器: gcc -w -o ser ser1.c 编译客户端: gcc -w -o cli cli.c readline.c
后台运行服务器: ./ser &
运行客户端: ./cli 127.0.0.1