source: trunk/user/tcp_chat/tcp_chat.c @ 690

Last change on this file since 690 was 682, checked in by alain, 3 years ago

Introduce three new applications:

  • windows : to test the FBF windows kernel manager
  • udp_chat : chat application based on UDP sockets.
  • tcp_chat : chat application based on TCP sockets (including packet loss recovery).
File size: 8.2 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////
2//  file   : tcp_chat.c
3//  author : Alain Greiner
4//  date   : december 2020
5///////////////////////////////////////////////////////////////////////////////////////
6//  This file describes a TCP chat application. Depending on the "is_server argument,
7//  it can be used to launch the the TCP client, or the TCP server application.
8//  The client send the first message. The server wait this first message.
9//  The 4 command line arguments are: is_server, local_ip_addr, remote_ip_addr, port
10///////////////////////////////////////////////////////////////////////////////////////
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <almosmkh.h>
16#include <unistd.h>
17#include <sys/socket.h>
18
19#define   BUF_SIZE       256
20
21////////////////////////////
22void client_chat( int fdid )
23{
24    char   buffer[BUF_SIZE];   // string buffer (for both send and receive)
25    int    size;               // string length (including NUL)
26    int    nbytes;             // number of characters actually sent or received
27
28    while( 1 )
29    {
30        //////// display client prompt to wait local client message ////////
31        printf("\n[local client] ");
32
33        // build local client message
34        size = get_string( buffer , BUF_SIZE );
35
36        // exit chat function when client message is the "exit" string
37        if( strncmp( "exit" , buffer , 4 ) == 0 )
38        {
39            printf("\n[client_chat] local message is <exit> => return to main\n" );
40            return;
41        }
42 
43        // send local client message
44        nbytes = send( fdid , buffer , size , 0 );
45
46        if( nbytes != size )
47        {
48            printf("\n[client_chat error] cannot send => return to main\n");
49            return;
50        }
51
52        ///////// display server prompt to wait remote server message ///////
53        printf("\n[remote server] ");
54
55        // receive remote server message
56        nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); 
57
58        if( nbytes < 0 )
59        {
60            printf("\n\n[client_chat error] cannot receive => return to main\n" );
61            return;
62        }
63        else if( nbytes == 0 )
64        {
65            printf("\n\n[client_chat] receive EOF => return to main\n" );
66            return;
67        }
68       
69        // display remote server message
70        printf("%s\n", buffer );
71    }
72}  // end client_chat()
73
74
75////////////////////////////
76void server_chat( int fdid )
77{
78    char   buffer[BUF_SIZE];   // string buffer (for send and receive)
79    int    size;               // string length (including NUL)
80    int    nbytes;             // number of characters actually sent or received
81
82    while( 1 )
83    {
84        //////// display client prompt to wait remote client message ///////
85        printf("\n[remote client] ");
86
87        // receive remote client message
88        nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); 
89
90        if( nbytes < 0 )
91        {
92            printf("\n\n[server_chat error] cannot receive => return to main\n" );
93            return;
94        }
95        else if( nbytes == 0 )
96        {
97            printf("\n\n[server_chat] receive EOF => return to main\n" );
98            return;
99        }
100       
101        // display remote client message
102        printf("%s\n", buffer );
103
104        //////// display server prompt to wait local server message //////
105        printf("\n[local server] ");
106
107        // build local server message
108        size = get_string( buffer , BUF_SIZE );
109
110        // exit chat function when server message is the "exit" string
111        if( strncmp( "exit" , buffer , 4 ) == 0 )
112        {
113            printf("\n[server_chat] local message is <exit> => return to main\n" );
114            return;
115        }
116
117        // send local server message
118        nbytes = send( fdid , buffer , size , 0 ); 
119
120        if( nbytes != size )
121        {
122            printf("\n[server_chat error] cannot send => return to main\n");
123            return;
124        }
125    } 
126}  // end server_chat()
127
128///////////////////////
129int main( int     argc,
130          char ** argv )
131{
132    int                  pid;          // process identifier
133    int                  fdid;         // file index of local socket
134    int                  new_fdid;     // file index for new derver socket
135    int                  error;
136
137    sockaddr_in_t        local_sin;    // local socket internet address
138    sockaddr_in_t        remote_sin;   // remote socket internet address
139
140    int                  addr_length = sizeof(sockaddr_t);
141
142    unsigned long long   start_cycle;
143
144    // get  start cycle
145    get_cycle( &start_cycle );
146
147    // get PID
148    pid = getpid();
149
150    // get arguments
151    if( argc != 4 )
152    {
153        printf("\n  usage : tcp_chat is_server local_addr remote_addr port\n");
154        exit( 0 );
155    }
156
157    int is_server    = atoi( argv[0] );
158    int local_addr   = atoi( argv[1] );
159    int remote_addr  = atoi( argv[2] );
160    int port         = atoi( argv[3] );
161 
162    if( is_server )
163    printf("\n[%s] SERVER / pid %x / cycle %d / local %x  / remote %x / port %x\n",
164    __FUNCTION__, pid, (unsigned int)start_cycle, local_addr,  remote_addr, port );
165    else           
166    printf("\n[%s] CLIENT / pid %x / cycle %d / local %x  / remote %x / port %x\n",
167    __FUNCTION__, pid, (unsigned int)start_cycle, local_addr,  remote_addr, port );
168
169    // initialize local_sin
170    local_sin.sin_domain = HTONS( AF_INET );
171    local_sin.sin_addr   = HTONL( local_addr );
172    local_sin.sin_port   = HTONS( port );
173
174    // initialize remote_sin
175    remote_sin.sin_domain = HTONS( AF_INET );
176    remote_sin.sin_addr   = HTONL( remote_addr );
177    remote_sin.sin_port   = HTONS( port );
178
179    // create local TCP socket
180    fdid = socket( AF_INET,
181                   SOCK_STREAM,
182                   0 );
183
184    if( fdid < 0 )
185    {
186        printf("\n[error] in %s : cannot create socket\n", __FUNCTION__ );
187        exit( 0 );
188    }
189    else
190    {
191        printf("\n[%s] created socket[%x,%d]\n", __FUNCTION__, pid, fdid );
192    }
193
194    // bind local socket
195    error = bind( fdid,
196                  (sockaddr_t *)(&local_sin),
197                  sizeof(sockaddr_t) );
198    if( error )
199    {
200        printf("\n[error] in %s : cannot bind socket[%x,%d]\n", __FUNCTION__, pid, fdid );
201        exit( 0 );
202    }
203    else
204    {
205        printf("\n[%s] client socket[%x,%d] bound\n", __FUNCTION__, pid, fdid );
206    }
207
208    ///////////////
209    if( is_server )
210    {
211        // Listen client connection request
212        error = listen( fdid , 1 );
213                     
214        if( error )
215        {
216            printf("\n[error] in %s : socket[%x,%d] cannot listen\n",
217            __FUNCTION__, pid, fdid );
218            exit( 0 );
219        }
220        else
221        {
222            printf("\n[%s] listening socket[%x,%d] wait client connection\n",
223            __FUNCTION__ , pid , fdid );
224        }
225
226        // get new chat socket fdid
227        new_fdid = accept( fdid,
228                           (sockaddr_t *)&remote_sin,
229                           &addr_length );
230
231        if( new_fdid < 0 )
232        {
233            printf("\n[error] in %s : listening socket[%x,%d] cannot accept\n",
234            __FUNCTION__, pid, fdid );
235            exit( 0 );
236        }
237        else
238        {
239            printf("\n[%s] new socket[%x,%d] connected to client\n",
240            __FUNCTION__, pid, new_fdid  );
241        }
242
243        // call server_chat function
244        server_chat( new_fdid ); 
245 
246        // 6 close both listen and chat sockets
247        close( fdid );
248        close( new_fdid );
249
250        printf("\n[tcp_server] closed both <listen> & <chat> sockets\n" );
251    }
252    //////////////////
253    else  // is_client
254    {
255        // connect to remote socket
256        error = connect( fdid,
257                         (sockaddr_t *)(&remote_sin),
258                         sizeof(sockaddr_t) );
259        if( error )
260        {
261            printf("\n[error] in %s : socket[%x,%d] cannot connect\n",
262            __FUNCTION__ , pid , fdid );
263            exit( 0 );
264        }
265        else
266        {
267            printf("\n[%s] socket[%x,%d] connected to server\n",
268            __FUNCTION__ , pid, fdid );
269        }
270
271        // call client_chat function
272        client_chat( fdid );
273
274        // close local socket
275        close( fdid );
276
277        printf("\n[%s] client closed socket[%x,%d]\n",
278        __FUNCTION__, pid, fdid );
279    }
280
281    exit(0);
282
283    return 0;
284}
Note: See TracBrowser for help on using the repository browser.