用epoll实现简易的telnet

我承认这篇文章有点标题党,呵呵。其实就是一个能和服务器建立全双工通信的客户端而已,用epoll机制实现。

上代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

//注意,不能一次性输入超过MAXLINE个的字符,否则程序会出错
#define MAXLINE 1024

//发生了致命错误,输出错误后立即退出  
void error_quit(const char *str)      
{      
	perror(str);  
	exit(1);      
} 

//关闭连接,退出程序
void close_connect(int sockfd)
{
	close(sockfd);
	printf("The connect have shutdown\n");
	exit(0);
}

int main(int argc, char **argv)
{
	int epfd, sockfd, nfs, tfd;   
	int readn, i, res;
	struct sockaddr_in servaddr;         
	struct epoll_event ev, events[256]; 
	char buffer[MAXLINE];

	if( argc != 3 )    
		error_quit("usage: mytelnet <Address> <Port>");   

	//创建epoll事件处理机
	epfd = epoll_create(256);       
	if( -1 == epfd )  
		error_quit("epoll_create error");  

	//创建用于TCP协议的套接字     
	sockfd = socket(AF_INET, SOCK_STREAM, 0);    
	memset(&servaddr, 0, sizeof(servaddr));    
	servaddr.sin_family = AF_INET;    
	servaddr.sin_port = htons( atoi(argv[2]) );    
	res = inet_pton(AF_INET, argv[1], &servaddr.sin_addr);  

	//连接服务器
	if( res != 1 )
		error_quit("inet_pton error");   
	res = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));    
	if( res < 0 )
		error_quit("connect error");

	//注册socket事件
	ev.data.fd = sockfd;
	ev.events = EPOLLIN|EPOLLET; 
	res = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);        
	if( res < 0 )
		error_quit("epoll_ctl error");
	//注册标准输入事件
	ev.data.fd = STDIN_FILENO;
	ev.events = EPOLLIN|EPOLLET; 
	res = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);     
	if( res < 0 )
		error_quit("epoll_ctl error");

	//开始事件循环
	while( 1 )
	{
		nfs = epoll_wait(epfd, events, 20, 500);
		for(i=0; i<nfs; i++)
		{
			if(events[i].events & EPOLLIN)     
			{
				tfd = events[i].data.fd;
				memset(buffer, 0, MAXLINE);
				readn = read(tfd, buffer, MAXLINE);

				//有网络消息传来了
				if( sockfd == tfd )
				{
					if ( readn < 0)         
					{          
						// Connection Reset:你连接的那一端已经断开了,      
						//而你却还试着在对方已断开的socketfd上读写数据!        
						if (errno == ECONNRESET)        
							close_connect(sockfd);
						else 
							error_quit("read error");
					}
					//连接正常关闭
					else if ( readn == 0 )       
						close_connect(sockfd);
					else
						printf("%s", buffer);
				}
				//标准输入
				if( STDIN_FILENO == tfd )
				{
					ev.data.fd = sockfd;      
					ev.events = EPOLLOUT|EPOLLET;       
					res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);      
					if( -1 == res )  
						error_quit("epoll_ctl error");  
				}
			}

			//如果有数据发送      
			else if(events[i].events & EPOLLOUT)       
			{      
				sockfd = events[i].data.fd;      
				write(sockfd, buffer, readn);   

				//注册用于读操作的文件描述符和事件      
				ev.data.fd = sockfd;      
				ev.events = EPOLLIN|EPOLLET;      
				res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);      
				if( -1 == res )  
					error_quit("epoll_ctl error");  
			}      
		}
	}
	return 0;
}

编译与运行命令:
gcc mytelnet.c -o mytelnet -levent
./mytelnet 127.0.0.1 8877
用于测试的服务器:http://blog.csdn.net/aaa20090987/article/details/8769585

你可能感兴趣的:(用epoll实现简易的telnet)