1. 程式人生 > >Linux C高階程式設計——網路程式設計之包裹函式

Linux C高階程式設計——網路程式設計之包裹函式

                                    Linux網路程式設計(六)——包裹函式

                         宗旨:技術的學習是有限的,分享的精神是無限的。

         系統呼叫不能保證每次都成功,必須進行出錯處理。包裹函式就是把一般函式加了出錯處理。包裹函式首字母大寫。

/*************************************************************************
    > File Name: wrap.h
    > Author: libang
    > Mail: 
[email protected]
> Created Time: 2016年04月06日 星期三 17時23分35秒 ************************************************************************/ #ifndef WRAP_H #define WRAP_H #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/socket.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> void perr_exit(const char *s); int Accept(int fd,struct sockaddr *sa,socklen_t *salenptr); void Bind(int fd,const struct sockaddr* sa,socklen_t salen); void Connect(int fd,const struct sockaddr* sa,socklen_t salen); void Listen(int fd,int backlog); int Socket(int family,int type,int protocol); ssize_t Read(int fd,void *ptr,size_t nbytes); ssize_t Write(int fd,const void *ptr,size_t nbytes); ssize_t Readn(int fd,void *vptr,size_t n); ssize_t Writen(int fd,const void*vptr,size_t n); static ssize_t my_read(int fd,char *ptr); static Readline(int fd,void *vptr,size_t maxlen); void Close(int fd); #endif
/*************************************************************************
    > File Name: wrap.c
    > Author: libang
    > Mail: [email protected]
    > Created Time: 2016年04月06日 星期三 17時53分25秒
 ************************************************************************/

#include "wrap.h"

void perr_exit(const char *s)
{
  perror(s);
  exit(1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t* salenptr)
{
  int newfd;
again:
  if((newfd = accept(fd, sa, salenptr)) < 0)
  {
    if((errno == ECONNABORTED) || (errno == EINTR))
    {
      goto again;
    }
    else
    {
      perr_exit("accept error");
    }
  }

  return newfd;
}

void Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{
  if(bind(fd, sa, salen) < 0)
  {
    perr_exit("bind error");
  }
}

void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
  if(connect(fd, sa, salen) < 0)
  {
    perr_exit("connect error");
  }
}

void Listen(int fd, int backlog)
{
  if(listen(fd, backlog) < 0)
  {
    perr_exit("listen error");
  }
}

int Socket(int family, int type, int protocol)
{
  int socketfd;
  if((socketfd = socket(family, type, protocol)) < 0)
  {
    perr_exit("socket error");
  }

  return socketfd;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
  ssize_t n;
again:
  if((n = read(fd, ptr, nbytes)) == -1)
  {
    if(errno == EINTR)
    {
      goto again;
    }
    else
    {
      return -1;
    }
  }
  return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
  ssize_t n;
again:
  if((n = write(fd, ptr, nbytes)) == -1)
  {
    if(errno == EINTR)
    {
      goto again;
    }
    else
    {
      return -1;
    }
  }

  return n;
}

ssize_t Readn(int fd, void *vptr, size_t n)
{
  size_t nleft;
  ssize_t nread;
  char *ptr;

  ptr = vptr;
  nleft = n;
  while(nleft > 0)
  {
    if((nread = read(fd, ptr, nleft)) < 0)
    {
      if(errno == EINTR)
      {
        nread = 0;
      }
      else
      {
        return -1;
      }
    }
    else if(nread == 0)
    {
      break;
    }

    nleft -= nread;
    ptr += nread;
  }

  return (n - nleft);
}

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(nwritten < 0 && errno == EINTR)
      {
        nwritten = 0;
      }
      else
      {
        return -1;
      }
    }

    nleft -= nwritten;
    ptr += nwritten;
  }

  return n;
}

static ssize_t my_read(int fd, char *ptr)
{
  static int read_cnt;
  static char *read_ptr;
  static char read_buf[100];

  if(read_cnt <= 0)
  {
again:
    if((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)
    {
      if(errno == EINTR)
      {
        goto again;
      }
      else
      {
        return -1;
      }
    }
    else if(read_cnt == 0)
    {
      return 0;
    }
    read_ptr = read_buf;
  }

  read_cnt--;
  *ptr = *read_ptr++;
  return 1;
}

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++)
  {
    if((rc = my_read(fd, &c)) == 1)
    {
      *ptr++ = c;
      if(c == '\n')
      {
        break;
      }
    }
    else if(rc == 0)
    {
      *ptr = 0;
      return n - 1;
    }
    else
    {
      return (n - 1);
    }
  }

  *ptr = 0;
  return n;
}

void Close(int fd)
{
  if(close(fd) == -1)
  {
    perr_exit("close error");
  }
}
/*************************************************************************
    > File Name: server.c
    > Author: libang
    > Mail: [email protected] 
    > Created Time: 2016年04月6日 星期日 23時51分26秒
 ************************************************************************/

#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000

int main(int argc,char *argv[])
{
	struct sockaddr_in servaddr,cliaddr;
	socklen_t cliaddr_len;
	int sockfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];//系統定義的巨集TCP:16  UDP:46
	int i,n;
	/* 伺服器端開始建立sockfd描述符 */ 
	sockfd = Socket(AF_INET,SOCK_DGRAM,0);// AF_INET:IPV4;SOCK_STREAM:TCP

	/* 伺服器端填充 sockaddr結構 */ 
	bzero(&servaddr,sizeof(servaddr));// 初始化,置0
	servaddr.sin_family = AF_INET;		// Internet
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);// (將本機器上的long資料轉化為網路上的long資料)和任何主機通訊  //INADDR_ANY 表示可以接收任意IP地址的資料,即繫結到所有的IP
	//server_addr.sin_addr.s_addr=inet_addr("192.168.1.1");  //用於繫結到一個固定IP,inet_addr用於把數字加格式的ip轉化為整形ip
	servaddr.sin_port = htons(SERV_PORT);	// (將本機器上的short資料轉化為網路上的short資料)埠號

	/* 捆綁sockfd描述符到IP地址 */ 
	Bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

	printf("Accept connections ...\n");
	while(1)
	{
		cliaddr_len = sizeof(cliaddr);//地址長度
		n = recvfrom(sockfd,buf,MAXLINE,0,(struct sockaddr *)&cliaddr,&cliaddr_len );//接收客戶端資訊到buf中
		if(n == -1)
			perr_exit("recvfrom error");
		printf("recvfrom from %s at PORT %d\n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));

		for(i=0;i<n;i++)
			buf[i] = toupper(buf[i]);//小寫轉大寫
		n = sendto(sockfd,buf,n,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));//把buf內容傳送sockfd中發給客戶端
		if(n == -1)
			perr_exit("sendto error");
	}
	
	return 0;
}
/*************************************************************************
    > File Name: client.c
    > Author: libang
    > Mail: [email protected] 
    > Created Time: 2016年04月6日 星期一 23時03分44秒
 ************************************************************************/

#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc,char *argv[])
{
	struct sockaddr_in servaddr;
	int sockfd,n;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];//系統定義的巨集TCP:16  UDP:46
	socklen_t servaddr_len;

	/* 伺服器端開始建立sockfd描述符 */
	sockfd = Socket(AF_INET,SOCK_DGRAM,0);

	/* 客戶程式填充服務端的資料 */ 
	bzero(&servaddr,sizeof(servaddr));// 初始化,置0
	servaddr.sin_family = AF_INET;	// IPV4
	inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);// IP地址
	servaddr.sin_port = htons(SERV_PORT);// (將本機器上的short資料轉化為網路上的short資料)埠號

	while(fgets(buf,MAXLINE,stdin) != NULL)//從鍵盤輸入內容
	{
		/*傳送buf到sockfd中*/
		n = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&servaddr,sizeof(servaddr));
		if(n == -1)
			perr_exit("recvfrom error");

		n = recvfrom(sockfd,buf,MAXLINE,0,NULL,0);
		if(n == -1)
			perr_exit("recvfrom error");

		Write(STDOUT_FILENO,buf,n);//寫到標準輸出中
	}

	Close(sockfd);

	return 0;
}