LT和ET模式

  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 }

LT和ET模式_第1张图片

首先输入telnet 192,168.255.129登录到服务器后,然后再输入telnet 192.168.255.129 4444

 

LT和ET模式_第2张图片

但是奇怪的是为什么总是接受的数据多两个呢?而且

我观察上面的代码,第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
View Code
[root@linux ~]# telnet 192.168.255.129 4444
Trying 192.168.255.129...
Connected to 192.168.255.129.
Escape character is '^]'.
123
123456789123  
View Code

 

上面是以ET模式在运行,下来我们用LT模式来执行

LT和ET模式_第3张图片

当我们关闭服务器后,再重启可能出现如图这样的情况,我们可以在等下大概2分钟,这是因为连接还没完全释放!

LT和ET模式_第4张图片

CR, LF, CR/LF区别与关系

前言

在文本处理中,CRCarriageReturn),LFLineFeed),CR/LF是不同操作系统上使用的换行符,具体如下:

  • Dos和Windows采用回车+换行CR/LF表示下一行
  • 而UNIX/Linux采用换行符LF表示下一行
  • 苹果机(MAC OS系统)则采用回车符CR表示下一行

区别

CR与LF区别如下:

  • CR用符号r表示,十进制ASCII代码是13,十六进制代码为0x0D
  • LF使用n符号表示,ASCII代码是10,十六制为0x0A

所以Windows平台上换行在文本文件中是使用0d 0a两个字节表示,而UNIX和苹果平台上换行则是使用0a0d一个字节表示。

问题

一般操作系统上的运行库会自动决定文本文件的换行格式。如一个程序在Windows上运行就生成CR/LF换行格式的文本文件,而在Linux上运行就生成LF格式换行的文本文件。在一个平台上使用另一种换行符的文件文件可能会带来意想不到的问题,特别是在编辑程序代码时。有时候代码在编辑器中显示正常,但在编辑时却会因为换行符问题而出错。很多文本/代码编辑器带有换行符转换功能,使用这个功能可以将文本文件中的换行符在不同格式单互换。

在不同平台间使用FTP软件传送文件时,在ASCII文本模式传输模式下,一些FTP客户端程序会自动对换行格式进行转换。经过这种传输的文件字节数可能会发生变化。如果你不想FTP修改原文件,可以使用bin模式(二进制模式)传输文本。

你可能感兴趣的:(模式)