【UNIX网络编程】自学epoll,使用epoll修改回射服务器程序

前言:

在阅读并且转载了华科师兄的ipoll详解 的文章之后,感觉自己需要亲手使用epoll实现一个程序才行,不然得来的知识是记不住的,于是决定修改UNIX网络编程中的回射客户端程序,改用epoll来实现。

程序流程:

  传递一个ip地址给主程序,主程序连接成功后把标准输入流和套接字传递给str_cli子程序,该子程序就使用epoll实现。最终实现代码如下所示:

/*************************************************************************
	> File Name: strcli_epoll.c
	> Author: yinwen
	> Mail: [email protected] 
	> Created Time: Sat 13 Jun 2015 04:21:01 PM CST
 ************************************************************************/

#include "unp.h"
#include <sys/epoll.h>
#define EPOLLSIZE 1024

void str_cli(FILE* fp, int sockfd)
{
	char sendline[MAXLINE], recvline[MAXLINE];
	struct epoll_event events;
	int epollfd;
	int i,n, fpno, num, j;

	int stdineof =0;

	epollfd = epoll_create(EPOLLSIZE);
	fpno = fileno(fp);
	events.events = EPOLLOUT;
	events.data.fd = fpno;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, fpno, &events);

	events.data.fd = sockfd;
	events.events = EPOLLIN;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &events);

	struct epoll_event* res = calloc(EPOLLSIZE, sizeof(struct epoll_event));

	j =0;
	while((n = epoll_wait(epollfd, res, 4, -1)) >0)
	{
		for(i=0; i<n; i++)
		{
			printf("res[0].data.fd is %d and events is %d\n", res[0].data.fd, res[0].events);
			printf("res[1].data.fd is %d and events is %d\n", res[1].data.fd, res[1].events);
			if(res[i].data.fd == sockfd)
			{
				printf("now is in sockfd\n");
				if((num = read(sockfd,recvline, MAXLINE)) ==0)
				{
					if(stdineof ==1)
						return;
					else
						err_quit("str_cli: server terminated prematurely");
				}
				write(fpno, recvline, num);
			}
		}
			if(res[i].data.fd == fpno)
			{
				printf("now is in stdin\n");
				if(( num = read(fpno, sendline, MAXLINE)) ==0) 
				{
					stdineof =1;
					shutdown(sockfd, SHUT_WR);
					continue;
				}
				write(sockfd, sendline, num);
			}
		j++;
		printf("j is %d\n", j);
	}
	
}
遇到的问题:

编写这个程序的时候本来以为能轻松解决的,没想到居然花了我3个小时来调试。

1.epoll_ctl使用错误:

最容易犯的错误直接就犯了,忘记调用该函数把套接字加入了。

2.if判断错误:

这里又犯了一个脑残错误,if里比较返回的套接字,居然使用的一个=号,变成了赋值,结果程序一直阻塞在read调用之上

3.判断的先后顺序:

我现在贴在上面的代码,在调用了epoll_wait之后,先对比套接字,再对比标准输入。这才是正确的顺序。我第一次编写的时候顺序反过来了。所以第一次调用的epoll_wait的时候返回结果是只有标准输入可以写,写入之后发给了服务器程序,然后服务器程序发回给套接字。但是这时需要重新调用epoll_wait才能收到可读的信息。

第二次调用epoll_wait,当然标准输入还是可以写的,于是要先输入第二次发送的结果,然后才会进入读取套接字的程序。所以最后的结果变成了这次写入字符串下一次返回。

为了解决这个问题,我最开始使用gdb进行调试,并且好好复习了gdb的使用,然后发现收到的数据是对的,只不过顺序不对,于是决定在程序里直接加入输出顺序的printf语句,终于发现是顺序反了。

其实这个问题UNIX程序设计的书里所有的代码都避免了。我之前照着书敲代码的时候完全没有想到这个问题。果然东西还是得自己重头亲手写出来才行。

输入结果截图:

这个结果里包含了很多排序的输出,不过不影响结果

【UNIX网络编程】自学epoll,使用epoll修改回射服务器程序_第1张图片

你可能感兴趣的:(【UNIX网络编程】自学epoll,使用epoll修改回射服务器程序)