学习 UNIX网络编程卷1:套接字 笔记1-实现一个简单的回射客户服务器程序

一:客户端程序

1、头文件:unp.h


#ifndef _unp_h
#define _unp_h
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h>  /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h>  /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h>  /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h>  /* for Unix domain sockets */
#define MAXLINE 4096
#define LISTENQ 5
#define SERV_PORT   9877
int Socket(int sockfd, int type, int protocol);
void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
void Listen(int sockfd,int backlog);
void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
void Write(int fd,void *buf,size_t count);
void Close(int sockfd);
void err_sys(char *err_str);
int Fork();
void str_echo(int sockfd);
ssize_t writen(int fd, char *buf, size_t n);
ssize_t Writen(int fd, char *buf, size_t n);
void str_cli(FILE *fp, int sockfd);
ssize_t readline(int fd, void *vptr, size_t maxlen);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
#endif
2、客户端主程序:clien.c

#include "unp.h"

int main(int argc,char **argv)
{
    char ip_addr[20];
    int sockfd;
    struct sockaddr_in servaddr;
    if (argc != 2)
    {
        err_sys("usage:clien <IPaddress>");
        return -1;
    }

    bzero(&servaddr, sizeof(servaddr));
    bzero(ip_addr,sizeof(ip_addr));
    strcpy(ip_addr,argv[1]);
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_addr.s_addr = inet_addr(ip_addr);
    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    str_cli(stdin,sockfd);

    return 0;

}

3、客户端包裹函数:pack.c

#include "unp.h"

void err_sys(char *err_str)
{
  perror(err_str);
}

int Socket(int sockfd, int type, int protocol)
{
  int n=0;
  if ((n=socket(sockfd,type,protocol))<0)
  {
    err_sys("socket error");
  }
  return n;
}

void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
  int n=0;
  if ((n = bind(sockfd,myaddr,addrlen))<0)
  {
    err_sys("bind error");
  }
}

void Listen(int sockfd,int backlog)
{
  char *ptr=NULL;
  if ((ptr=getenv("LISTENQ"))!=NULL)
  {
    backlog=atoi(ptr);
  }
  if (listen(sockfd,backlog)<0)
  {
    err_sys("listen error");
  }
}

void Connect(int sockfd,const struct sockaddr *servaddr, socklen_t addrlen)
{
  if(connect(sockfd,servaddr,addrlen)<0)
  {
    err_sys("connect error");
  }
  else
  {
    printf("connect success!\n");
  }
}

int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
  int n;
  again:
    if ((n=accept(sockfd,cliaddr,addrlen))<0)
    {
#ifndef EPROTO
      if(errno == EPROTO || errno == ECONNABORTED)
#else
      if(errno == ECONNABORTED)
#endif
      {
          goto again;
      }
      else
      {
        err_sys("accept error");
      }
    }
  return n;
}

ssize_t Writen(int fd,char *buf, size_t n)
{
  ssize_t ret;
  ret = writen(fd,buf,n);
  if (ret < 0)
  {
    err_sys("writen error");
    return -1;
  }
  return ret;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
  ssize_t n;
  n=readline(fd,vptr,maxlen);
  if (n<0)
  {
    err_sys("readline error");
    return -1;
  }
  return n;
}

4、客户端功能行函数:func.c

#include "unp.h"
ssize_t writen(int fd, char *buf, size_t n)
{
  size_t nleft;
  ssize_t nwritten;
  char *ptr;
  ptr = buf;
  nleft = n ;
  while(nleft > 0)
  {
    nwritten = write(fd, ptr, nleft);
    if (nwritten < 0 && errno == EINTR)
    {
      nwritten = 0;      
    }
    else if (nwritten < 0)
    {
      err_sys("write error");
      return -1;
    }

    nleft -= nwritten;
    ptr += nwritten;
  }
  return n;
}

void str_echo(int sockfd)
{
  ssize_t n;
  char buf[MAXLINE];
  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 error");
  }
}
ssize_t readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n,rc;
    char c,*ptr;
    ptr = vptr;
    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;
}

void str_cli(FILE *fp, int sockfd)
{
    char sendline[MAXLINE],recvline[MAXLINE];
    bzero(sendline,sizeof(sendline));
    bzero(recvline,sizeof(recvline));

    while(fgets(sendline,MAXLINE,fp) != NULL)
    {
        Writen(sockfd,sendline,strlen(sendline));
        if (Readline(sockfd, recvline, MAXLINE) == 0)
        {
            err_sys("str_cli Readline error");
        }
        fputs(recvline, stdout);
    }
}

5、客户端Makefile

clien:clien.o pack.o func.o
    gcc clien.o pack.o func.o -o clien
clien.o:clien.c unp.h 
    gcc -c clien.c -o clien.o
pack.o:pack.c unp.h 
    gcc -c pack.c -o pack.o
func.o:func.c unp.h 
    gcc -c func.c -o func.o    
.PHONY:clean
clean:
    rm -f *.o

二:服务器程序

1、头文件:unp.h

#ifndef _unp_h
#define _unp_h
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h>  /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h>  /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h>  /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h>  /* for Unix domain sockets */
#define MAXLINE 4096
#define LISTENQ 5
#define SERV_PORT   9877
typedef void (*sighandler_t)(int);
sighandler_t Signal(int signum, sighandler_t handler);//signal函数的包裹函数
int Socket(int sockfd, int type, int protocol);//socket的包裹函数
void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);//bind函数的包裹函数
void Listen(int sockfd,int backlog);//listen函数的包裹函数
void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);//connect函数的包裹函数
int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);//accept函数的包裹函数
void Write(int fd,void *buf,size_t count);//write函数的包裹函数
void Close(int sockfd);//关闭套接字函数close的包裹函数
void err_sys(char *err_str);//错误输出函数
int Fork();//fork函数的包裹函数
void str_echo(int sockfd);//回射函数
ssize_t writen(int fd, char *buf, size_t n);//写n个字符的writen函数
ssize_t Writen(int fd, char *buf, size_t n);//writen函数的包裹函数
void sig_chlid(int signo);//信号控制函数sig_child
#endif


2、服务器主程序:serv.c

#include "unp.h"
void sig_chld(int );


int main(int argc, char const *argv[])
{
    int listenfd,connfd;
    pid_t childpid;
    socklen_t clilen;
    struct sockaddr_in cliaddr,servaddr;
    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);//服务器端口赋值
    Bind(listenfd,(struct sockaddr*)&servaddr, sizeof(servaddr));//绑定监听套接字与服务器的端口
    Listen(listenfd, LISTENQ);  //监听
    Signal(SIGCHLD, sig_chld);  //回收僵死子进程
    while(1)
    {
        clilen = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);//accept创建已连接套接字connfd
        if (connfd<0) {
          if(errno == EINTR)//处理系统中断
          {
            continue;
          }
          else
          {
            err_sys("accept error");
          }
        }
        if ((childpid = Fork()) == 0)//创建子进程
        {
            Close(listenfd);//子进程关闭监听套接字
            str_echo(connfd);//调用回射函数
            exit(0);
        }
        else//父进程
        {
            Close(connfd);//父进程关闭已连接套接字
        }


    }
    return 0;
}

3、包裹函数:pack.c

#include "unp.h"


void err_sys(char *err_str)
{
  perror(err_str);
}


int Socket(int sockfd, int type, int protocol)
{
  int n=0;
  if ((n=socket(sockfd,type,protocol))<0)
  {
    err_sys("socket error");
  }
  printf("socket success!sockfd=%d\n",n);
  return n;
}


void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
  int n=0;
  if ((n = bind(sockfd,myaddr,addrlen))<0)
  {
    err_sys("bind error");
  }
  printf("bind success\n");
}


void Listen(int sockfd,int backlog)
{
  char *ptr=NULL;
  if ((ptr=getenv("LISTENQ"))!=NULL)
  {
    backlog=atoi(ptr);
  }
  if (listen(sockfd,backlog)<0)
  {
    err_sys("listen error");
  }
  printf("listen success\n");
}


void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
{
  if(connect(sockfd,servaddr,addrlen)<0)
  {
    err_sys("connect error");
  }
  printf("connect success!\n");
}


int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
  int n;
  again:
    if ((n=accept(sockfd,cliaddr,addrlen))<0)
    {
#ifndef EPROTO
      if(errno == EPROTO || errno == ECONNABORTED)
#else
      if(errno == ECONNABORTED)
#endif
      {
          goto again;
      }
      else
      {
        err_sys("accept error");
      }
    }
  return n;
}


void Write(int fd,void *buf,size_t count)
{
	ssize_t n;
	n=write(fd,buf,count);
	if(n!=count)
	{
		err_sys("write error");
	}


}
void Close(int sockfd)
{
	if(close(sockfd)==-1)
	{
		err_sys("close error");
    }
}


int Fork()
{
  pid_t pid;
  if ((pid = fork()) < 0)
  {
    err_sys("fork error");
  }
  else
    return pid;
}


ssize_t Writen(int fd,char *buf, size_t n)
{
  ssize_t ret;
  ret = writen(fd,buf,n);
  if (ret < 0)
  {
    err_sys("writen error");
    return -1;
  }
  return ret;
}


sighandler_t Signal(int signum, sighandler_t handler)
{
  if (signal(signum, handler)==SIG_ERR)
  {
    err_sys("signal error");
    exit(-1);
  }
  
}

4、功能性函数:func.c

#include "unp.h"


ssize_t writen(int fd, char *buf, size_t n)
{
  size_t nleft;
  ssize_t nwritten;
  char *ptr;
  ptr = buf;
  nleft = n ;
  while(nleft > 0)
  {
    nwritten = write(fd, ptr, nleft);
    if (nwritten < 0 && errno == EINTR)
    {
      nwritten = 0;
    }
    else if (nwritten < 0)
    {
      err_sys("write error");
      return -1;
    }


    nleft -= nwritten;
    ptr += nwritten;
  }
  return n;
}


void str_echo(int sockfd)
{
  ssize_t n;
  char buf[MAXLINE];
  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 error");
  }
}


void sig_chld(int signum)
{
    pid_t pid;
    int stat;


    while((pid = waitpid(-1, &stat, WNOHANG)) >0 )
    {
      printf("chlid %d terminated!\n",pid);
    }
    // pid = wait(&stat);
    // printf("child %d terminated!\n", pid);
    return ;
}
5、服务器Makefile

serv:serv.o pack.o func.o
    gcc serv.o pack.o func.o -o serv
serv.o:serv.c unp.h
    gcc -c serv.c -o serv.o
pack.o:pack.c unp.h
    gcc -c pack.c -o pack.o
func.o:func.c unp.h
    gcc -c func.c -o func.o
.PHONY:clean
clean:
    rm -f *.o




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值