linux网络编程-出错处理函数封装

系统调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息。如果上次每次函数的调用都要加判断,那太过于繁琐。
为使错误处理的代码不影响主程序的可读性,我们把与socket相关的一些系统函数加上错误处理代码包装成新的函数,做成一个模块wrap.c,这个wrap.c还是原有函数的参数,只不过将函数首字母大写了。
在这里插入图片描述
上面这个goto…就这么写的,那就有吧,这里是因为accept可能会被信号打断,使用goto再调用一次。

socket中不能使用fread和fwrite,因为这俩函数想要文件指针,但是在socket中只有文件描述符

wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_
void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int 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);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
#endif

wrap.c

#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
void perr_exit(const char *s)
{
	perror(s);
	exit(1);
}
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
	int n;
	again:
	if ( (n = accept(fd, sa, salenptr)) < 0) {
		if ((errno == ECONNABORTED) || (errno == EINTR))
			goto again;
		else
			perr_exit("accept error");
	}
	return n;
}
int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
	int n;
	if ((n = bind(fd, sa, salen)) < 0)
		perr_exit("bind error");
	return n;
}
int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
	int n;
	if ((n = connect(fd, sa, salen)) < 0)
		perr_exit("connect error");
	return n;
}
int Listen(int fd, int backlog)
{
	int n;
	if ((n = listen(fd, backlog)) < 0)
		perr_exit("listen error");
	return n;
}
int Socket(int family, int type, int protocol)
{
	int n;
	if ( (n = socket(family, type, protocol)) < 0)
		perr_exit("socket error");
	return n;
}
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;
}
int Close(int fd)
{
	int n;
	if ((n = close(fd)) == -1)
		perr_exit("close error");
	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;
			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 -1;
	}
	*ptr = 0;
	return n;
}

client.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<ctype.h>
#include<sys/socket.h>
#include<arpa/inet.h>


void sys_err(const char *str)
{
 perror(str);
 exit(1);
}


int main(int argc,char *argv[])
{
  
   //创建一个socket  
  int cfd=Socket(AF_INET,SOCK_STREAM,0);
   
  //创建服务端的地址结构
  struct sockaddr_in serv_addr;//服务器地址结构
  bzero(&serv_addr,sizeof(serv_addr));
  serv_addr.sin_family=AF_INET;
  serv_addr.sin_port=htons(22222);//设置端口
  int dst;
  inet_pton(AF_INET, "127.0.0.1", (void *)&dst);
  serv_addr.sin_addr.s_addr=dst;
  
  //连接服务端
  Connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
  
 //与服务端通信的主逻辑  
  int count=10;
  char buf[1024];
  while(--count)
  {
     fgets(buf,sizeof(buf),stdin);
     int r= Write(cfd,buf,strlen(buf));
     int ret= read(cfd,buf,sizeof(buf));
     printf("Wrte r======%d",r);
     int len=Read(cfd,buf,sizeof(buf));
     printf("Read len  =============%d",len);     
     Write(STDOUT_FILENO,buf,len);
  }

  
  Close(cfd);
  return 0;
  
}

tcpserver.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<ctype.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include "wrap.h"


int main(int argc,char *argv[])
{
  //创建一个socket
  int lfd=0;
  lfd=Socket(AF_INET,SOCK_STREAM,0);
  
  //bind函数绑定ip和端口
  struct sockaddr_in server_addr;
  server_addr.sin_family=AF_INET;
  server_addr.sin_port=htons(22222);
  server_addr.sin_addr.s_addr=(htonl)INADDR_ANY;
  Bind(lfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
  
  //设置同时监听个数
  Listen(lfd,128);
  
  printf("wait for client connect....\n");  
  
  //accept
  struct sockaddr_in client_addr;//创建客户端地址
  socklen_t cliAddrLen=sizeof(client_addr);
  int cfd=Accept(lfd,(struct sockaddr *)&client_addr,&cliAddrLen);
  printf("cfd======%d",cfd);   
 
  char client_ip[1024];
  printf("\n client ip:%s  port:%d\n",
                inet_ntop(AF_INET,&client_addr.sin_addr,client_ip,sizeof(client_ip)),
                ntohs(client_addr.sin_port)
                    );
  
  char buf[BUFSIZ];
  while(1)
  {
      
     int ret= Read(cfd,buf,sizeof(buf));
      
      int i;
     for(i=0;i<ret;i++)
      {
       printf("%c",buf[i]);
       buf[i]=toupper(buf[i]);
     
      }
  
      Write(cfd,buf,ret);
  
  }
  Close(lfd);
  Close(cfd);
  
  return 0;
  

}

编译命令

gcc wrap.c tcpserver.c -o server

同理client.c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贪睡的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值