socket网络编程封装错误处理函数

本文档介绍了对socket相关函数的增强封装,包括出错打印、退出机制,以及读写特定字节数和读取行的功能,提升代码可读性和开发效率。重点在于Socket操作的稳健性和性能提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对socket相关函数进行封装加入出错打印和退出功能,并封装了读写n个字节和读一行的函数,以提高代码可读性和开发效率

  1. 仅将函数名首字母改成大写的函数任可跳转man手册
  2. 除了Setcockopt函数被固定为端口复用功能,其他的函数参数保持不变,只是添加了出错打印和退出功能

cs_dev.h

#pragma once
#ifndef _CS_DEV_H_
#define _CS_DEV_H_

#include <unistd.h>
#include <sys/socket.h>

//输出错误信息并退出
void perr_exit(const char* s);	

//以下函数均内嵌 perr_exit 函数
int Socket(int domain, int type, int protocol);
int Setsockopt(int sockfd); //设置端口复用
int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int Close(int fd);

//防止信号导致读写失败
ssize_t Read(int fd, void *buf, size_t count);
ssize_t Write(int fd, const void *buf, size_t count);
//读n个字节
ssize_t Readn(int fd, void* vptr, size_t n);
//写n个字节
ssize_t Writen(int fd, const void* vptr, size_t n);
//读一行
ssize_t Readline(int fd, void* vptr, size_t maxlen);

#endif

c/s_dev.c

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>        
#include <sys/socket.h>

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

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

int Setsockopt(int sockfd)
{
	int opt = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &opt, sizeof(opt))) {
    	perr_exit("setsockopt");
    }
}

int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
	int n;
	again:
	if ( (n = accept(sockfd, addr, addrlen)) < 0) {
		if ((errno == ECONNABORTED) || (errno == EINTR))
			goto again;
		else
			perr_exit("accept error");
	}
	return n;
}

int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int n;
	if ((n = bind(sockfd, addr, addrlen)) < 0)
		perr_exit("bind error");
	return n;
}

int Listen(int sockfd, int backlog)
{
	int n;
	if ((n = listen(sockfd, backlog)) < 0)
		perr_exit("listen error");
	return n;
}
int Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int n;
	if ((n = connect(sockfd, addr, addrlen)) < 0)
		perr_exit("connect error");
	return n;
}

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

ssize_t Write(int fd, const void *buf, size_t count)
{
	ssize_t n;
again:
	if ( (n = write(fd, buf, count)) == -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;
}

demo

利用socket错误处理函数进行客户端和服务端的开发。

server.c 将接收到的客户端字符串信息转成大写并发送回客户端

#include "cs_dev.h"
#include <ctype.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

#define SOCKPROT 8888

void waitChild(int signum)
{
	int pid;
	
	while ((pid = waitpid(0, NULL, WNOHANG)) > 0) {
		printf("wait process pid:%d \n", pid);
	}
}

int main(void)
{
	int sockfd = 0;
	int c_fd = 0;
	char buf[1024] = {0};
	struct sockaddr_in sockaddr;
	struct sockaddr_in c_addr;

	sockfd = Socket(AF_INET, SOCK_STREAM, 0);

	Setsockopt(sockfd);

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port   = htons(SOCKPROT);
	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	Bind(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

	signal(SIGCHLD, waitChild);
	
	Listen(sockfd, 10);

	char dstIp[32] = {0};
	int c_addr_len = sizeof(c_addr);
	while (1) {
		c_fd = Accept(sockfd, (struct sockaddr*)&c_addr, &c_addr_len);
		printf("IP:%s PROT:%d connect...\n", \
			inet_ntop(AF_INET, &c_addr.sin_addr, dstIp, sizeof(dstIp)), \
			ntohs(c_addr.sin_port));

		int ret = fork();
		if (ret == -1) 
			perr_exit("fork");
		else if (ret == 0){
			while (1) {
				int n = Read(c_fd, buf, sizeof(buf));
				if(n == 0) {
					printf("IP:%s PROT:%d disconnect...\n", \
						inet_ntop(AF_INET, &c_addr.sin_addr, dstIp, sizeof(dstIp)/sizeof(char)), \
						ntohs(c_addr.sin_port));
					Close(c_fd);
					exit(0);
				} else {
					for (int i = 0; i < n; i++) {
						buf[i] = toupper(buf[i]);
					}
					Write(c_fd, buf, n);
				}
			}
		}
	}
	
	Close(sockfd);
	
	return 0;
}

client.c

#include <stdio.h>
#include <string.h>
#include "cs_dev.h"
#include <stdlib.h>
#include <arpa/inet.h>

#define SOCKPORT 8888
#define IP "127.0.0.1"

int main(void) 
{
	int sockfd = 0;
	char buf[1024] = {0};
	struct sockaddr_in sockaddr;

	sockfd = Socket(AF_INET, SOCK_STREAM, 0);

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port   = htons(SOCKPORT);
	inet_pton(AF_INET, IP, &sockaddr.sin_addr);
	Connect(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

	while (fgets(buf, sizeof(buf), stdin) != NULL) {
		int n = Write(sockfd, buf, strlen(buf));
		
		n = Read(sockfd, buf, n);
		if (n == 0) {
			printf("the other side has been closed.\n");
			break;
		} else
			Write(STDOUT_FILENO, buf, n);
	}

	Close(sockfd);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值