Reputation:
I just read the recv
manual and I have some problem in understanding what the Manual says and what the actually happens in my Program.
The manual say:
RETURN VALUE
... return the number of bytes received, or -1 if an error occurred.
So I have the following program which can be compiled and tested:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 8888
#define MAX_LEN_MSG 50
#define BACKLOG 5
int socket_sckt ( struct sockaddr_in *server );
int bind_sckt ( struct sockaddr_in *server, const size_t server_addr_len );
int listen_sckt ( void );
int accept_sckt ( struct sockaddr_in *client, const size_t *client_addr_len );
int getsockname_sckt ( struct sockaddr_in *server, const size_t *server_addr_len );
int getpeername_sckt ( struct sockaddr_in *client, const size_t *client_addr_len );
ssize_t recv_sckt ( char *const msg );
int serverID;
int clientID;
int main( void )
{
char msg[ MAX_LEN_MSG] = { 0 };
struct sockaddr_in server;
struct sockaddr_in client;
size_t server_addr_len = sizeof( server );
size_t client_addr_len = sizeof( client );
memset( &server, 0, server_addr_len);
memset( &client, 0, client_addr_len);
/// Socket, Bind and Listen
serverID = socket_sckt ( &server );
bind_sckt ( &server, server_addr_len );
listen_sckt( );
getsockname_sckt( &server, &server_addr_len );
printf("Start Server on...\n" );
clientID = accept_sckt ( &client, &client_addr_len );
getpeername_sckt( &client, &client_addr_len );
printf("Connected IP(%s) on Port(%d)\n", inet_ntoa( client.sin_addr), ntohs( client.sin_port));
ssize_t recv_ret = recv_sckt ( msg );
if ( recv_ret > 0 )
{
printf("The MSG is %s | Len = %zu\n", msg, strlen( msg ) );
printf("The recived length is %zd\n", recv_ret );
}
}
int socket_sckt ( struct sockaddr_in *server )
{
int socket_ret = socket( AF_INET , SOCK_STREAM , 0);
if ( socket_ret == -1 )
{
printf( "Error, socket()\n" );
fprintf( stderr, "socket: %s (%d)\n", strerror( errno ), errno );
exit( EXIT_FAILURE );
}
server->sin_family = AF_INET;
server->sin_addr.s_addr = INADDR_ANY;
server->sin_port = htons( PORT );
return socket_ret;
}
int bind_sckt ( struct sockaddr_in *server, const size_t server_addr_len )
{
int bind_ret = bind( serverID, ( struct sockaddr * )server, ( socklen_t )server_addr_len );
if ( bind_ret == -1 )
{
printf( "Error, bind()\n" );
fprintf( stderr, "bind: %s (%d)\n", strerror( errno ), errno);
exit ( EXIT_FAILURE );
}
return bind_ret;
}
int listen_sckt ( void )
{
int listen_ret = listen( serverID, BACKLOG );
if ( listen_ret == -1 )
{
printf( "Error, listen()\n" );
fprintf( stderr, "listen: %s (%d)\n", strerror( errno ), errno );
exit( EXIT_FAILURE );
}
return listen_ret;
}
int accept_sckt ( struct sockaddr_in *client, const size_t *client_addr_len )
{
int accept_ret = accept( serverID, (struct sockaddr*) client, (socklen_t*) client_addr_len);
if ( accept_ret == -1 )
{
printf( "Error, accept()\n" );
fprintf( stderr, "accept: %s (%d)\n", strerror( errno ), errno );
exit( EXIT_FAILURE );
}
return accept_ret;
}
int getsockname_sckt ( struct sockaddr_in *server, const size_t *server_addr_len )
{
int getsockname_sckt = getsockname( serverID, ( struct sockaddr* ) server, ( socklen_t* ) server_addr_len );
if ( getsockname_sckt == -1 )
{
printf( "Error, getsockname()\n" );
fprintf( stderr, "getsockname: %s (%d)\n", strerror( errno ), errno );
exit ( EXIT_FAILURE );
}
return getsockname_sckt;
}
int getpeername_sckt ( struct sockaddr_in *client, const size_t *client_addr_len )
{
int getpeername_ret = getpeername( clientID, ( struct sockaddr* ) client, ( socklen_t* ) client_addr_len );
if ( getpeername_ret == -1 )
{
printf( "Error, getpeername()\n" );
fprintf( stderr, "getpeername: %s (%d)\n", strerror( errno ), errno );
exit ( EXIT_FAILURE );
}
return getpeername_ret;
}
ssize_t recv_sckt ( char *const msg )
{
ssize_t recv_ret = recv( clientID, msg, MAX_LEN_MSG, 0 );
if ( recv_ret == -1 )
{
printf( "Error, recv()\n" );
fprintf( stderr, "recv: %s (%d)\n", strerror( errno ), errno );
exit( EXIT_FAILURE );
}
msg[ strcspn( msg, "\n" ) ] = 0;
msg[ recv_ret ] = 0;
return recv_ret;
}
Now if I connect to this server with a client:
Please enter your name: George
Connect to Server: 192.168.0.103:8888
You are: 192.168.0.103:60878
On the server side I get:
Start Server on...
Connected IP(192.168.0.103) on Port(60878)
The MSG is George | Len = 6
The recived length is 31
Why is the recived length 31
and not 6
?
Upvotes: 0
Views: 435
Reputation: 948
The recv()
function does not \0
terminate the buffer, zero out the buffer in the recv_sckt()
function.
ssize_t recv_sckt ( char *const msg )
{
// Zero out the buffer
memset(msg, '\0', MAX_LEN_MEG);
ssize_t recv_ret = recv( clientID, msg, MAX_LEN_MSG, 0 );
if ( recv_ret == -1 )
{
printf( "Error, recv()\n" );
fprintf( stderr, "recv: %s (%d)\n", strerror( errno ), errno );
exit( EXIT_FAILURE );
}
msg[ strcspn( msg, "\n" ) ] = 0;
msg[ recv_ret ] = 0;
return recv_ret;
}
Update:
Aaaah, I just realised - the msg[strcspn(msg, '\n')] = 0;
line is replacing the first \n
with a 0 (or \0
).
So in effect it's rendering part of the buffer unreadable.
Maybe instead of
return recv_ret;
Try:
return strlen(msg);
Hope that solves it, I'm not sure what the server is actually sending to you.
An alternative method might be to remove that msg[strcspn(msg, '\n')] = 0;
line, although I'm unsure what junk may lie beyond that \n
so may have undesired results.
Plus you'd still need to make sure you terminate the buffer properly.
Update #2
I'm not sure about the server and what it's sending, that line I pointed out:
msg[strcspn(msg, '\n')] = 0;`
Is basically finding the first \n
character in the return buffer and turning it into a 0 or \0
character. The \0
tells functions like printf()
where the buffer ends.
However, the recv()
function returns a number telling you how many bytes are received. Let's imagine for arguments' sake that the server is returning this string:
George\nabcdef
The msg[strcspn(msg, '\n')] = 0;
line finds that \n
and replaces it with a \0
(or a literal 0 value).
So recv()
is telling you, hey look - I actually read in 13
bytes, but you made some of those bytes inaccessible because they lie beyond the \0
terminator.
You'll find loads of stuff about string termination in c here on SO and with a Google search. You could do as I said in my initial response and zero-terminate the entire buffer:
memset(msg, '\0', buffer_size);
So that the data is zero-terminated, I'd try that - remove the msg[strcspn(msg, '\n')] = 0;
line and print out the full buffer including that \n
and whatever lies beyond it, maybe junk, maybe just whitespace...who knows?!
Hope this makes sense.
Upvotes: 2