1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <assert.h> 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <errno.h> 9 #include <string.h> 10 #include <fcntl.h> 11 #include <stdlib.h> 12 #include <sys/epoll.h> 13 #include <pthread.h> 14 #include <libgen.h> 15 #include <strings.h> 16 #define MAX_EVENT_NUMBER 1024 17 #define BUFFER_SIZE 10 18 19 int setnonblocking( int fd ) 20 { 21 int old_option = fcntl( fd, F_GETFL ); 22 int new_option = old_option | O_NONBLOCK; 23 fcntl( fd, F_SETFL, new_option ); 24 return old_option; 25 } 26 void addfd( int epollfd, int fd, int enable_et ) 27 { 28 struct epoll_event event; 29 event.data.fd = fd; 30 event.events = EPOLLIN; 31 if( enable_et ) 32 { 33 event.events |= EPOLLET; 34 } 35 epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 36 setnonblocking( fd ); 37 } 38 39 void lt( struct epoll_event * events, int number, int epollfd, int listenfd ) 40 { 41 char buf[ BUFFER_SIZE ]; 42 for ( int i = 0; i < number; i++ ) 43 { 44 int sockfd = events[i].data.fd; 45 if ( sockfd == listenfd ) 46 { 47 struct sockaddr_in client_address; 48 socklen_t client_addrlength = sizeof( client_address ); 49 int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 50 addfd( epollfd, connfd, 0 ); 51 } 52 else if ( events[i].events & EPOLLIN ) 53 { 54 printf( "event trigger once\n" ); 55 memset( buf, '\0', BUFFER_SIZE ); 56 int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ); 57 if( ret <= 0 ) 58 { 59 close( sockfd ); 60 continue; 61 } 62 printf( "get %d bytes of content: %s\n", ret, buf ); 63 } 64 else 65 { 66 printf( "something else happened \n" ); 67 } 68 } 69 } 70 71 void et( struct epoll_event *events, int number, int epollfd, int listenfd ) 72 { 73 char buf[ BUFFER_SIZE ]; 74 for ( int i = 0; i < number; i++ ) 75 { 76 int sockfd = events[i].data.fd; 77 if ( sockfd == listenfd ) 78 { 79 struct sockaddr_in client_address; 80 socklen_t client_addrlength = sizeof( client_address ); 81 int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 82 addfd( epollfd, connfd, 1 ); 83 } 84 else if ( events[i].events & EPOLLIN ) 85 { 86 printf( "event trigger once\n" ); 87 while( 1 ) 88 { 89 memset( buf, '\0', BUFFER_SIZE ); 90 int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ); 91 if( ret < 0 ) 92 { 93 if( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) 94 { 95 printf( "read later\n" ); 96 break; 97 } 98 close( sockfd ); 99 break; 100 } 101 else if( ret == 0 ) 102 { 103 close( sockfd ); 104 } 105 else 106 { 107 108 printf( "get %d bytes of content: %s\n", ret, buf ); 109 110 } 111 } 112 } 113 else 114 { 115 printf( "something else happened \n" ); 116 } 117 } 118 } 119 120 int main( int argc, char* argv[] ) 121 { 122 if( argc <= 2 ) 123 { 124 printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 125 return 1; 126 } 127 const char* ip = argv[1]; 128 int port = atoi( argv[2] ); 129 130 int ret = 0; 131 struct sockaddr_in address; 132 bzero( &address, sizeof( address ) ); 133 address.sin_family = AF_INET; 134 inet_pton( AF_INET, ip, &address.sin_addr ); 135 address.sin_port = htons( port ); 136 137 int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 138 assert( listenfd >= 0 ); 139 140 ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 141 assert( ret != -1 ); 142 143 ret = listen( listenfd, 5 ); 144 assert( ret != -1 ); 145 146 struct epoll_event events[MAX_EVENT_NUMBER]; 147 int epollfd = epoll_create( 5 ); 148 assert( epollfd != -1 ); 149 addfd(epollfd,listenfd,1); 150 151 while( 1 ) 152 { 153 int ret = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 154 if (ret < 0) 155 { 156 printf( "epoll failure\n" ); 157 break; 158 } 159 160 // lt( events, ret, epollfd, listenfd ); 161 et( events, ret, epollfd, listenfd ); 162 } 163 164 close( listenfd ); 165 return 0; 166 }
首先输入telnet 192,168.255.129登录到服务器后,然后再输入telnet 192.168.255.129 4444
但是奇怪的是为什么总是接受的数据多两个呢?而且
我观察上面的代码,第90行int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ),至第108行 printf( "get %d bytes of content: %s\n", ret, buf );
可以看出估计是把enter键包含进去了,所以多出两个字节!
我们来测试下是否是我猜测的那样,下来验证下:
将62行的代码修改为如下:
else
{
for(i=0;i<ret;i++)
printf( "get %d bytes of content: %d\n", i, buf[i] );
}
[root@linux Desktop]# gcc 9-3mtlt.c -std=gnu99 [root@linux Desktop]# ./a.out 192.168.255.129 4444 event trigger once get 0 bytes of content: 49 get 1 bytes of content: 50 get 2 bytes of content: 51 get 3 bytes of content: 13 get 4 bytes of content: 10 event trigger once get 0 bytes of content: 49 get 1 bytes of content: 50 get 2 bytes of content: 51 get 3 bytes of content: 52 get 4 bytes of content: 53 get 5 bytes of content: 54 get 6 bytes of content: 55 get 7 bytes of content: 56 get 8 bytes of content: 57 event trigger once get 0 bytes of content: 49 get 1 bytes of content: 50 get 2 bytes of content: 51 get 3 bytes of content: 13 get 4 bytes of content: 10
[root@linux ~]# telnet 192.168.255.129 4444 Trying 192.168.255.129... Connected to 192.168.255.129. Escape character is '^]'. 123 123456789123
上面是以ET模式在运行,下来我们用LT模式来执行
当我们关闭服务器后,再重启可能出现如图这样的情况,我们可以在等下大概2分钟,这是因为连接还没完全释放!
在文本处理中,CR(CarriageReturn),LF(LineFeed),CR/LF是不同操作系统上使用的换行符,具体如下:
CR/LF
表示下一行LF
表示下一行CR
表示下一行CR与LF区别如下:
r
表示,十进制ASCII代码是13
,十六进制代码为0x0D
n
符号表示,ASCII代码是10
,十六制为0x0A
所以Windows平台上换行在文本文件中是使用0d 0a
两个字节表示,而UNIX和苹果平台上换行则是使用0a
或0d
一个字节表示。
一般操作系统上的运行库会自动决定文本文件的换行格式。如一个程序在Windows上运行就生成CR/LF
换行格式的文本文件,而在Linux上运行就生成LF
格式换行的文本文件。在一个平台上使用另一种换行符的文件文件可能会带来意想不到的问题,特别是在编辑程序代码时。有时候代码在编辑器中显示正常,但在编辑时却会因为换行符问题而出错。很多文本/代码编辑器带有换行符转换功能,使用这个功能可以将文本文件中的换行符在不同格式单互换。
在不同平台间使用FTP软件传送文件时,在ASCII文本模式传输模式下,一些FTP客户端程序会自动对换行格式进行转换。经过这种传输的文件字节数可能会发生变化。如果你不想FTP修改原文件,可以使用bin模式(二进制模式)传输文本。