readn和writen函数实现通信

readn()和writen()并非任何标准的组成部分,这两个函数是我们自己定义的,只是为了使用方便。以下是笔者自己实现的readn和writen函数,可用于客户端和服务器端进行通信,测试时先将服务器端程序运行,然后再运行客户端程序,客户端在linux终端下输入消息,回车变可发送给服务器daunt,只后服务器端会回射消息给客户端。

read()和writen()函数可用于处理tcp传输的粘包问题。

 

server.c

 

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/types.h>

#define ERR_EXIT(m) do{ perror(m); exit(EXIT_FAILURE); }while(0)

ssize_t readn(int fd, void *buf, size_t count)
{
        int ret;
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char *) buf;

        while(nleft>0)
        {
                if((nread = read(fd, bufp, nleft)) <0)       
                {
			if(errno == EINTR)  /* 被信号中断的情况 */
				continue;
                        return -1;
                }
        
                else if(nread == 0)  /* 对等方关闭 */
                	return count - nleft;

		bufp += nread;
		nleft -= nread;
	}
	return count;	
}

ssize_t writen(int fd, const void  *buf, size_t count)
{
	size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char *) buf;

        while(nleft>0)
        {
		/* 通常只要bufp中数据大于nleft,就不会引起阻塞 */
                if((nwritten = write(fd, bufp, nleft)) <0)
                {
                        if(errno == EINTR)  /* 被信号中断的情况 */
                                continue;
                        return -1;
                }

                else if(nwritten == 0)  
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }
        return count;
}

void do_service(int conn)
{
	char recvbuf[1024];
	while(1)
	{
		/* readn一次读取 sizeof(recvbuf), 也就是1024字节,如果发送方发送数据少于这么多,readn将会阻塞在此处 */
		memset(recvbuf, 0, sizeof(recvbuf));
		int ret = readn(conn, recvbuf, sizeof(recvbuf));
		printf("ret = %d\n", ret);
		if(ret == 0)
		{
			printf("client close.\n");
				break;//return -1;
		}
		else if(ret == -1)
			ERR_EXIT("readn error.");
		fputs(recvbuf, stdout);
		writen(conn, recvbuf, ret);	
	}	
}

int main(void)
{
	int listenfd;
	signal(SIGCHLD, SIG_IGN);  //避免僵尸进程signal(SIGCHLD, SIG_IGN);  //避免僵尸进程
	if((listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) <0)
		ERR_EXIT("socket error.");

	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;	
	servaddr.sin_port = htons(5188);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	int on = 1;
	if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
	{
		ERR_EXIT("setsockopt error.");
	}

	if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
		ERR_EXIT("bind error.");
	
	if(listen(listenfd, 8) < 0)
		ERR_EXIT("listen error.");

	struct sockaddr_in peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	int connfd;
	pid_t pid;
	
	while(1)
	{
		if((connfd = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0)
			ERR_EXIT("accept error.");
		else 
			printf("connect success.\n");
		printf("ip = %s, port = %d\n", inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));

		pid = fork();
		if(pid == -1)
			ERR_EXIT("fork error.");
		
		/* 子进程 */
		if(pid == 0)
		{
			close(listenfd);
			do_service(connfd);
			exit(EXIT_SUCCESS);
		}
		else 
			close(connfd);
	}
		
	return 0;	
}

 

 

 

 

 

client.c

 

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <netinet/in.h>

#define ERR_EXIT(m) do{ perror(m); exit(EXIT_FAILURE); }while(0)

ssize_t readn(int fd, void *buf, size_t count)
{
        int ret;
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char *) buf;

        while(nleft>0)
        {
                if((nread = read(fd, bufp, nleft)) <0)
                {
                        if(errno == EINTR)  /* 被信号中断的情况 */
                                continue;
                        return -1;
                }

                else if(nread == 0)  /* 对等方关闭 */
			return count - nleft;

                bufp += nread;
                nleft -= nread;
        }
        return count;
}

ssize_t writen(int fd, const void  *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char *) buf;

        while(nleft>0)
        {
                /* 通常只要bufp中数据大于nleft,就不会引起阻塞 */
                if((nwritten = write(fd, bufp, nleft)) <0)
                {
			if(errno == EINTR)  /* 被信号中断的情况 */
                                continue;
                        return -1;
                }

                else if(nwritten == 0)
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }
        return count;
}



int main(void)
{
	int sockfd;
	int writen_len;
	
	if((sockfd =socket(AF_INET, SOCK_STREAM, 0)) < 0)
		ERR_EXIT("socket error");

	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5188);
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) <0)
		ERR_EXIT("connect error.");
	
	char sendbuf[1024];
	char recvbuf[1024];
	while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
	{
		writen_len = writen(sockfd, sendbuf, sizeof(sendbuf));
		printf("writen_len = %d\n", writen_len);
		if(writen_len < 0)
		{
			printf("writen error.\n");
		}
		readn(sockfd, recvbuf, sizeof(recvbuf));

		fputs(recvbuf, stdout);
		memset(sendbuf, 0, sizeof(sendbuf));
		memset(recvbuf, 0, sizeof(recvbuf));
	}
	close(sockfd);
	return 0;
}

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值