C socket programming how to recieve multiple messages? - c

i have a server/client application and i am trying to get the server to read each message the client sends to it and send it back to the client to be printed. so far i have the server reading the first message and sending that to the client and that prints fine, but when the second message is sent from the client, i try to print it from the HandleTcpClient function to test it and it just prints null, i am not sure if it is receiving it correctly
client code:
#include <stdio.h> //include standard input/output library
#include <stdlib.h> //include standard libraries
#include <string.h> //include string headers
#include <unistd.h> //add definitions for constansts and functions
#include <sys/types.h> // include definitions for different data types
#include <sys/socket.h> //include socket support
#include <netinet/in.h> //define internet protocol functions
#include <arpa/inet.h> //define internet protocol functions
#include "Practical.h" //include practical header file
int main(int argc, char *argv[]) {
char myIP[16];
unsigned int myPort;
struct sockaddr_in server_addr,myaddr;
char username[] = "CharlieA";
if (argc < 2 || argc > 3) // Test for correct number of arguments
DieWithUserMessage("Parameter(s)",
"<Server Address> [<Server Port>]");
char *servIP = argv[1]; // First arg: server IP address (dotted quad)
// Third arg (optional): server port (numeric). 7 is well-known echo port
in_port_t servPort = atoi(argv[2]); //21
printf("serv port: %d\n",servPort);
// Create a reliable, stream socket using TCP //23
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//this block of code creates a reliable tcp stream socket and checks what the returned integer is from the socket function, the returned function will give a integer that descibes the socket. if this is 0 then kill the socket and show the user an error message.
if (sock < 0)
DieWithSystemMessage("socket() failed"); //26
// Construct the server address structure //28
struct sockaddr_in servAddr; // Server address
memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure
servAddr.sin_family = AF_INET; // IPv4 address family
// Convert address
int rtnVal = inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
if (rtnVal == 0)
DieWithUserMessage("inet_pton() failed", "invalid address string");
else if (rtnVal < 0)
DieWithSystemMessage("inet_pton() failed");
servAddr.sin_port = htons(servPort); // Server port
myaddr.sin_addr.s_addr = INADDR_ANY;
// Establish the connection to the echo server
if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
DieWithSystemMessage("connect() failed");
//get address of bound socket after connect function call (binds automatically with connect method)
bzero(&myaddr,sizeof(myaddr));
int len = sizeof(myaddr);
getsockname(sock,(struct sockaddr *) &myaddr, &len);
inet_ntop(AF_INET, &myaddr.sin_addr, myIP, sizeof(myIP)); //convert network address to string
myPort = ntohs(myaddr.sin_port); //convert from netshort to hostbyte order
//getlocal ip address to be sent to server
char *echoString=(char*)malloc(13*sizeof(char));
sprintf(echoString,"netsrv type0 %s %s-%u\r\n",username,myIP,myPort); //generate request string
size_t echoStringLen = strlen(echoString); // Determine input length //44
size_t iplen = strlen(myIP);
// Send the string to the server
ssize_t numBytes = send(sock,echoString, echoStringLen, 0);
printf("sent: %s", echoString);
if (numBytes < 0) //sending string to server, number of bytes of the message is equal to return value of send function, if the number of bytes is less than 0 then do not send and say to user that the send failed
DieWithSystemMessage("send() failed");
else if (numBytes != echoStringLen)
DieWithUserMessage("send()", "sent unexpected number of bytes"); //51
// if the number of bytes is not equal to the input length of the string parsed as an argument then die with the message to the user saying sent unexpected number of bytes.
//send IP to server
send(sock,myIP,iplen,0); //send client IP
// Receive the same string back from the server //53
unsigned int totalBytesRcvd = 0; // Count of total bytes received
while (totalBytesRcvd < echoStringLen) {
char buffer[BUFSIZE]; // I/O buffer
/* Receive up to the buffer size (minus 1 to leave space for
a null terminator) bytes from the sender */
numBytes = recv(sock, buffer, BUFSIZE - 1, 0);
if (numBytes < 0)
DieWithSystemMessage("recv() failed");
else if (numBytes == 0)
DieWithUserMessage("recv()", "connection closed prematurely");
totalBytesRcvd += numBytes; // Keep tally of total bytes
buffer[numBytes] = '\0'; // Terminate the string!
fputs("Received: ", stdout); // Setup to print the echoed string
fputs(buffer, stdout); // Print the echo buffer
}
fputc('\n', stdout); // Print a final linefeed //70
close(sock);
exit(0);
}
//closing off connections to clean up data left over.
The second message is the send client IP commented line
Server:
#include <stdio.h> //include standard input/output library
#include <stdlib.h> //include standard libraries
#include <string.h> //include string headers
#include <sys/types.h> //add definitions for constansts and functions
#include <sys/socket.h> // include definitions for different data types
#include <netinet/in.h> //define internet protocol functions
#include <arpa/inet.h> //define internet protocol functions
#include "Practical.h" //include pactical
static const int MAXPENDING = 5; // Maximum outstanding connection requests
static const int servPort = 48031;
int main(int argc) {//run on command line = "echoSvr <port>";argc = 2 command and parameter- argv[0] = echoSvr and argv[1] = <port>
// Create socket for incoming connections
int servSock; // Socket descriptor for server
if ((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithSystemMessage("socket() failed");
// this block of code is creating a socket stream to accept the incoming connections from clients
// Construct local address structure
struct sockaddr_in servAddr; // Local address; internet socket address structure
memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure
servAddr.sin_family = AF_INET; // IPv4 address family
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface; host to network long[integer]
servAddr.sin_port = htons(servPort); // Local port; host to network short[integer]
// Bind to the local address
if (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0)//cast servaddr as generic socket address structure
DieWithSystemMessage("bind() failed");
// Mark the socket so it will listen for incoming connections
if (listen(servSock, MAXPENDING) < 0)
DieWithSystemMessage("listen() failed");
setvbuf (stdout, NULL, _IONBF, 0);
printf("Listening on port: %d \n" , servPort);
printf("awaiting connection from client.... \n");
// this block of code binds the socket to the address of the server and tells the binded to socket to begin listening in for connections coming from client machines
for (;;) { // Run forever
struct sockaddr_in clntAddr; // Client address
// Set length of client address structure (in-out parameter)
socklen_t clntAddrLen = sizeof(clntAddr);
// Wait for a client to connect
int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);
if (clntSock < 0)
DieWithSystemMessage("accept() failed");
//this block of code waits for a client to connect to the socket and then accepts the connection from the client and prints the clients details out to screen
// clntSock is connected to a client!
char clntName[INET_ADDRSTRLEN]; // String to contain client address
if (inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr, clntName,
sizeof(clntName)) != NULL)
printf("Handling client %s/%d\n", clntName, ntohs(clntAddr.sin_port));
else
puts("Unable to get client address");
HandleTCPClient(clntSock);
}
}
HandleTCPClient Function:
void HandleTCPClient(int clntSocket) {
char buffer[BUFSIZE]; // Buffer for echo string
char *clientIP;
unsigned int clientPort;
// Receive message from client
ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
if (numBytesRcvd < 0)
DieWithSystemMessage("recv() failed");
//get ip and port of clntSocket to apply to greeting string
// Send greeting string and receive again until end of stream
while (numBytesRcvd > 0) { // 0 indicates end of stream
// Echo message back to client
ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);
if (numBytesSent < 0)
DieWithSystemMessage("send() failed");
else if (numBytesSent != numBytesRcvd)
DieWithUserMessage("send()", "sent unexpected number of bytes");
// See if there is more data to receive
numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
if (numBytesRcvd < 0)
DieWithSystemMessage("recv() failed");
//recv client ip and assign to variable to hold
recv(clntSocket,clientIP,100,0);
printf("clientIP : %s" ,clientIP);
}
close(clntSocket); // Close client socket
}
i am trying to print the clientIP with the printf function and this is where i am getting a null, it just does not seem to be receiving it, there is a lot of code here, i am posting it all in case it is needed

That is a lot of code, so I didn't look at most of it. I did, however, notice:
char *echoString=(char*)malloc(13*sizeof(char));
sprintf(echoString,"netsrv type0 %s %s-%u\r\n",username,myIP,myPort);
Nowhere do you explain where that 13 comes from, but it is clearly not enough to hold the formatted string which sprintf will produce. It's enough to hold a 12-character string (plus the NUL terminator) which gets you up to netsrv type0. That needs to be fixed, since the sprintf will clobber random memory which doesn't belong to it, but that's probably not your immediate problem. (Use snprintf. Even simpler, if you're using Linux/OSX/FreeBSD, is asprintf.)
What I think might be your problem is this:
numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
//recv client ip and assign to variable to hold
recv(clntSocket,clientIP,100,0);
printf("clientIP : %s" ,clientIP);
You never look at the data received by the first recv() call. Perhaps you are under the misapprehension that each send somehow marks the data being sent so that recv will only read exactly the data sent by one send. That's not the case. TCP is a streaming protocol; the data is just an undistinguished series of bytes and each recv() receives whatever is available, subject to the size limit in the call. So it is quite possible that the result of both send() calls will show up in the first recv() call.
I think this is probably explained in whatever text/tutorial/guide you are using to write that code, but if not I strongly recommend finding a copy of W. R. Stevens' Unix Network Programming.
In short: If you want to send "messages", you need to figure out how to delimit them in a way that the receiver can tell where one message ends and the next one begins. A really simple strategy, used by many older internet protocols, is to end each message with a newline sequence and ensure that there are no newlines in any message.

Related

Creating Multiple Client and One Server for UDP application using select() system call with C

Help me to correct this program I want to create a server that can run indefinitely and can serve many clients and for that, I am using a select system call for UDP (User Datagram Protocol) application.
My issue is that this code is running for multiple clients in a different session that means after running for one client it stops and again when I start the server again then it can serve another client also.
I want my code to work indefinitely in one session only and serve as many clients as I want.
Server Code:-
'''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define port1 8080
#define MAXN 1024
#define TRUE 1
int main(){
int sockfd,sockfd1;
struct sockaddr_in servaddr,cliaddr;
char buffer[MAXN];
char buff[MAXN];
int max_clients=2,valread,new_socket;
char *hello = "Hello Client";
char *message = "hiiii Server";
struct timeval timeout;
timeout.tv_sec = 20;
timeout.tv_usec = 0;
//create socket 2
sockfd = socket(AF_INET, SOCK_DGRAM,0);
if(sockfd<0){
perror("Error Creating Socket0");
exit(1);
}
//memset(&servaddr, 0, sizeof(servaddr));
//memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port1);
servaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (const *)&servaddr, sizeof(servaddr))<0){
perror("Error in binding0 ");
exit(1);
}
//Use Select......
//I have created 2 socket having file deescriptor sockfd and sockfd1
int s;
int client_socket[2]={0,0};
fd_set readfds;
while(){
FD_ZERO(&readfds);
FD_SET(sockfd,&readfds);
//Let's say sockfd is max_fd
int max_fd = sockfd,sd,activity;
for(int i=0;i<2;i++){
sd = client_socket[i];
if(sd>0){
FD_SET(sd,&readfds);
}
if(sd>max_fd)
max_fd = sd;
}
activity = select( max_fd + 1 , &readfds , NULL , NULL , &timeout);
if ((activity < 0))
{
printf("select error");
}
int addrlen = sizeof(servaddr);
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(sockfd, &readfds))
{
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d\n " , new_socket , inet_ntoa(servaddr.sin_addr) , ntohs
(servaddr.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (int i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (int i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&servaddr , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(servaddr.sin_addr) , ntohs(servaddr.sin_port));
//Close the socket and mark as 0 in list for reuse
//close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = '\0';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
return 0;
}
'''
This is one of the Client Code and this code is running :-
'''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define MAXN 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXN];
char *hello = "Hello from Multipleclient";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("Error in socket creation");
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
int n, len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXN,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
Some minor things to start with:
In the client code, you do not initialize len before passing it to recvfrom. Also, it is of the wrong type (int instead of socklen_t). This can be corrected by defining len as socklen_t len = sizeof(servaddr); However, since you do not use the length or address anywhere, you can just pass in NULL for both. Also, UDP does not support MSG_WAITALL, so pass 0 instead for the flags. recvfrom(sockfd, (char *)buffer, MAXN, 0, NULL, NULL).
In the client code, you fill in the server IP address as IPADDR_ANY, i.e. 0.0.0.0, which is only valid when calling bind. You are calling sendto. When specifying a destination address, you probably want IPADDR_LOOPBACK for the local computer.
In the server code, the main while() loop is missing a condition inside the parenthesis, so the code does not even compile. You probably want while(1) for an infinite loop.
In the server code, in the call to bind, you are casting to the wrong type. (const *) means (const int *), but you want (const struct sockaddr *).
The biggest problem:
Based on the comments and code in the server code, you seem to think that UDP communication has persistent connections, and try to save client_socket values for these. However, UDP does not have persistent connection. There is no such thing as a client socket in this context. select does not tell you that a new "connection" is ready. Instead, it tells you that data has been received on your one and only UDP socket (sockfd). This is entirely unlike TCP, where you accept a connection that lasts until one side terminates it.
From the comments in the server code, it seems that you intend for clients to have persistent state in the server, at least enough to be recognized when they send more datagrams (otherwise they would always get the welcome message).
A possible way to make this work is the following:
// create and bind a UDP socket as you already do;
// initialize and empty list of clients;
while(1) {
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(cliaddr);
recvfrom(sockfd, buffer, bufferlen, /*flags*/ 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
// check whether cliaddr is in your list;
if (!is_in_list) {
// this is a new client
// add to list of clients;
// send welcome message;
}
// do something else, maybe echo back the buffer contents;
}
You will notice that the code does not actually use select anymore. select is unnecessary if you have nothing to do while waiting, and you only listen to one socket. If you are doing other stuff not shown in the question, you can add the select back at the top of the infinite loop, and only handle the UDP socket if sockfd is set in the readfds from select.
Also note that the client cannot actually receive answers from the server, since there is no persistent connection, and the client has not passed any socket to bind. And also note that UDP messages may get lost without warning, and you should make sure your code can deal with that. It seems that this client-server-strategy would be easier to implement using TCP.
As a side note, it is strongly recommended to enable warnings in your compiler. That would have caught the wrong type for the address length variables, as well as told you that new_socket is used but never set. It is polite to fix all warnings before posting a question, unless of course the question is about the warning.

message from client to server in C

I have such a task, I need to write the “client” code so that the message from the “client” is sent to the server (which was created by my teacher, ip “127.0.0.1”). After the message arrives at the server (for example, “Nursultan Nazarbayev”, the server will reply “ok” and the client should send “quit”)
I'm just learning C. How to make a break with the server? I wanted to send "quit", but this did not work, there was a constant error, how can I do this?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char message[2048];//=(char*)malloc(sizeof(char));// transmission message
char buf[sizeof(message)];
int port,ch;
//----------------------------------------------------------------------------
if(argc!=3){
printf("Wrong number of arguments!\nThere must be 2 arguments (Port, server ip-address)!\n");
exit(0);
}
int sock; // socket descriptor
struct sockaddr_in addr; // structure with address
struct hostent* hostinfo;
port = atoi(argv[1]);
hostinfo = argv[2];
sock = socket(AF_INET, SOCK_STREAM, 0); // create TCP socket
if(sock < 0)
{
perror("socket");
exit(1);
}
// Specify server parameters
addr.sin_family = AF_INET; // Internet domains
addr.sin_port = htons(port); // or any other port ...
addr.sin_addr.s_addr=inet_addr("hostinfo");
// addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
//addr.sin_addr.s_addr = inet_addr(host_ip);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) // establishing a connection to the server
{
perror("Connection");
exit(2);
}
while(1){//WHILE <---
//----------------------------------------------------------------------------
printf("Enter a message to the server (To exit: quit): ");
if (!strcmp(gets(message), "quit")){close(sock);return 0;}
//----------------------------------------------------------------------------
printf("sending a message to the server...\n");
send(sock, message, sizeof(message), 0); // sending a message to the server
int bytes_read = 0;
printf("Message Waiting\n");
bytes_read = recv(sock, buf, sizeof(message), 0);
printf("received %d bytes\tMessage: %s\n", bytes_read, buf); // receiving a message from the server
}//END_WHILE
return 0;
}
This probably is wrong:
addr.sin_addr.s_addr=inet_addr("hostinfo");
You are passing the literal string, "hostinfo" to the inet_addr() function. Meanwhile, you have a variable named hostinfo, to which you assign a string value, but you never use it anywhere in the program.
Maybe you meant to do this instead:
addr.sin_addr.s_addr=inet_addr(hostinfo);
P.S., I like long, descriptive names. If that was my program, the name of the variable would be something like, server_address_as_string.

C sockets: getsocketnane ip address is always 0.0.0.0

Hi i am programming a networking client in c and i am using the getsocketname function to return the IP and port of the socket i have created but for some reason the IP is always returned as 0.0.0.0 here is the code:
#include <stdio.h> //include standard input/output library
#include <stdlib.h> //include standard libraries
#include <string.h> //include string headers
#include <unistd.h> //add definitions for constansts and functions
#include <sys/types.h> // include definitions for different data types
#include <sys/socket.h> //include socket support
#include <netinet/in.h> //define internet protocol functions
#include <arpa/inet.h> //define internet protocol functions
#include "Practical.h" //include practical header file
int main(int argc, char *argv[]) {
char myIP[16];
unsigned int myPort;
struct sockaddr_in server_addr,myaddr;
if (argc < 3 || argc > 4) // Test for correct number of arguments
DieWithUserMessage("Parameter(s)",
"<Server Address> <Echo Word> [<Server Port>]");
char *servIP = argv[1]; // First arg: server IP address (dotted quad)
char *echoString = argv[2]; // Second arg: string to echo
// Third arg (optional): server port (numeric). 7 is well-known echo port
in_port_t servPort = (argc == 4) ? atoi(argv[3]) : 7; //21
// Create a reliable, stream socket using TCP //23
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//this block of code creates a reliable tcp stream socket and checks what the returned integer is from the socket function, the returned function will give a integer that descibes the socket. if this is 0 then kill the socket and show the user an error message.
if (sock < 0)
DieWithSystemMessage("socket() failed"); //26
// Construct the server address structure //28
struct sockaddr_in servAddr; // Server address
memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure
servAddr.sin_family = AF_INET; // IPv4 address family
// Convert address
int rtnVal = inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
if (rtnVal == 0)
DieWithUserMessage("inet_pton() failed", "invalid address string");
else if (rtnVal < 0)
DieWithSystemMessage("inet_pton() failed");
servAddr.sin_port = htons(servPort); // Server port
myaddr.sin_addr.s_addr = INADDR_LOOPBACK;
bzero(&myaddr,sizeof(myaddr));
int len = sizeof(myaddr);
getsockname(sock,(struct sockaddr *) &myaddr, &len);
inet_ntop(AF_INET, &myaddr.sin_addr, myIP, sizeof(myIP));
myPort = ntohs(myaddr.sin_port);
printf("local ip address : %s\n", myIP);
printf("local port: %u\n", myPort);
// Establish the connection to the echo server
if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
DieWithSystemMessage("connect() failed");
size_t echoStringLen = strlen(echoString); // Determine input length //44
// Send the string to the server
ssize_t numBytes = send(sock, echoString, echoStringLen, 0);
if (numBytes < 0) //sending string to server, number of bytes of the message is equal to return value of send function, if the number of bytes is less than 0 then do not send and say to user that the send failed
DieWithSystemMessage("send() failed");
else if (numBytes != echoStringLen)
DieWithUserMessage("send()", "sent unexpected number of bytes"); //51
// if the number of bytes is not equal to the input length of the string parsed as an argument then die with the message to the user saying sent unexpected number of bytes.
// Receive the same string back from the server //53
unsigned int totalBytesRcvd = 0; // Count of total bytes received
fputs("Received: ", stdout); // Setup to print the echoed string
while (totalBytesRcvd < echoStringLen) {
char buffer[BUFSIZE]; // I/O buffer
/* Receive up to the buffer size (minus 1 to leave space for
a null terminator) bytes from the sender */
numBytes = recv(sock, buffer, BUFSIZE - 1, 0);
if (numBytes < 0)
DieWithSystemMessage("recv() failed");
else if (numBytes == 0)
DieWithUserMessage("recv()", "connection closed prematurely");
totalBytesRcvd += numBytes; // Keep tally of total bytes
buffer[numBytes] = '\0'; // Terminate the string!
fputs(buffer, stdout); // Print the echo buffer
}
fputc('\n', stdout); // Print a final linefeed //70
close(sock);
exit(0);
}
//closing off connections to clean up data left over.
the port number returned is always 0 too, i am assigning the address of the myaddr struct to be loopback address so i believe it is supposed to return 127.0.0.1 as the IP but it isn't, i am sort of new to socket programming so my logic might not be perfect, i just cant see whats wrong here
It means that the socket hasn't been bound to a local address yet.
You need to get the local address after it has been bound, which happens automatically with the connect call.

Socket - sending a big string in c

I am trying to understand why my function dosnt sending the all string (Its send only 53576 elements from 365568:
This is the function I am using in the client side:
#define DATASIZEBUFFER 4000// 365568
void DieWithError(char *errorMessage);/* Error handling function */
void TcpClient ( char *servIP , unsigned short echoServPort , Hash_t *HashData)//(int argc, char *argv[])
{
int sock; //Socket descriptor
struct sockaddr_in ServAddr; //Echo server address
int bytesRcvd, totalBytesRcvd; //Bytes read in single recv()
//and total bytes read
// Create a reliable, stream socket using TCP
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError(" socket () failed") ;
// Construct the server address structure
memset(&ServAddr, 0, sizeof(ServAddr)); /* Zero out structure */
ServAddr.sin_family = AF_INET; /* Internet address family */
ServAddr.sin_addr.s_addr = inet_addr(servIP);/* Server IP address */
ServAddr.sin_port = htons(echoServPort); /* Server port */
// Establish the connection to the server
if (connect(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0)
DieWithError(" connect () failed") ;
for (;;)
{
// Send the string to the server //
if (send(sock, HashData->array , HashData->elementNumber, 0) != HashData->elementNumber)
{
printf ("Bytes Nedded to recived: %ld\nAnd (DATASIZEBUFFER) is %d\n", HashData->elementNumber , DATASIZEBUFFER);
DieWithError("send() sent a different number of bytes than expected");
}
}
send() does not guarantee that it would send all the data.
From send man page:
On success, these calls return the number of bytes sent. On error,
-1 is returned, and errno is set appropriately.
You can write a loop around send() and invoke it multiple times until all data is sent (or, error is returned). It could be something like the following (please modify it based on your needs):
size_t
Send(int sockfd, const void *buf, size_t len, int flag) {
size_t sent_total = 0;
for (int sent_now = 0; sent_total != len; sent_total += sent_now) {
sent_now = send(sockfd, buf + sent_total, len - sent_total, flag);
if (sent_now == -1) break;
}
if (sent_total != len) {
LOG("send requested = %zu, sent = %zu", len, sent_total);
}
return sent_total;
}
Update to address #Myst's comments:
Although the question did not mention it explicitly, I assumed that the sockets used are blocking, since there are no fcntl call. With that in mind, the following from send() man page explains the situation:
When the message does not fit into the send buffer of the socket,
send() normally blocks, unless the socket has been placed in
nonblocking I/O mode.
In nonblocking mode it would fail with the
error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be
used to determine when it is possible to send more data.
For non-blocking socket, the design need to be different and is outside the scope of this discussion.

Raw sockets: sendto() and recvfrom() not working

I am trying to write a client/server application using RAW sockets.
There are multiple problems:
When the client sends a message to the server using sendto() method, an error invalid argument is returned by sendto() method. Why this error message?. The corresponding code is marked under the section ERROR 1. The code of sendto() is commented in this post.
Since I have commented the send message part, the client should wait for a message; recvfrom() being a blocking system call. Instead, recvfrom() returns with a message E always. From where did this message arrive?. The corresponding code is marked as ERROR 2.
If I change protocol (3rd) argument in socket() to 0 or IPPROTO_RAW I get Protocol not supported error. Why these errors?
The operating system is Ubuntu.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h> // For the socket () etc. functions.
#include <netinet/in.h> // For IPv4 data struct..
#include <string.h> // For memset.
#include <arpa/inet.h> // For inet_pton ().
#define BUF_SIZE 30
void main ()
{
int rst; // Return status of functions.
/**************** Create a socket. *******************************/
int sfd; // Socket file descriptor.
sfd = socket (AF_INET, SOCK_RAW, IPPROTO_UDP); /*
* AF_INET --> IPv4, SOCK_RAW for Raw socket,
* 0 --> for any protocol. */
if (sfd == -1)
{
perror ("Client: socket error");
exit (1);
}
/*********** Server's address ***********************************/
struct sockaddr_in srv_addr;
socklen_t addrlen = sizeof (struct sockaddr_in);
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
srv_addr.sin_family = AF_INET; // Address is in IPv4 format.
// srv_addr.sin_port = htons (0); // Port number of the server.
rst = inet_pton (AF_INET, "127.0.0.1", &srv_addr.sin_addr); /* Note
* that third field should point to an in_addr (in6_addr). */
if (rst <= 0)
{
perror ("Client Presentation to network address conversion.\n");
exit (1);
}
/****************** ERROR 1 ************************************
******************* Sending message to the server. *************/
const int flags = 0;
const char *msg = "Hello";
/* rst = sendto (sfd, msg, strlen(msg)+1, flags,
(struct sockaddr *) &srv_addr,
sizeof (struct sockaddr_in));
if (rst < 0)
{
perror ("Client: Sendto function call failed");
exit (1);
}
else
printf ("Client: Sent data size = %d\n", rst);
*/
/******************* ERROR 2 ***********************************
******************* Receiving message from server. ************/
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
char buf[BUF_SIZE] = {'\0'};
rst = recvfrom (sfd, buf, BUF_SIZE, flags,
(struct sockaddr *) &srv_addr,
&addrlen);
if (rst < 0)
{
perror ("Client: couldn't receive");
exit (1);
}
printf ("Message from server = |%s|\n", buf);
/* Address of the server. */
const char *buf2 = inet_ntop (AF_INET,
(struct sockaddr *) &srv_addr, buf, BUF_SIZE);
if (buf2 == NULL)
{
perror ("Client: Conversion of sender's address to presentation failed");
exit (1);
}
printf ("Servers address, = %s\n", buf2);
close (sfd);
}
SOCK_RAW is not for use with UDP. SOCK_DGRAM is correct. For a tutorial, see:
a tutorial from Rutgers
edit: overlooked the init of the srv_addr... sorry.
using AF_INET + SOCK_RAW socket you can send anything - the payload is just added on top of the IP-layer. the IPPROTO_UDP just tells the kernel what the next layer will be (the layer your payload is added to) and which value the protocol field of the IP header must be set to. so to stay save (if you go to send raw data) set the protocol to something not commonly used).
you need the permission to create a raw socket. this commonly means: start as root, create the socket and then drop the privileges.
q2: this is the message you send to yourself (and a strong indication that your code somehow worked). The 'E' is just the first byte (0x45) in the IP-header - version 4 and header length 5. just dump the whole buffer..., eg.
printf ("Message from server = |");
for (i = 0; i < rst; i++)
printf("%c", isprint(buf[i]) ? buf[i] : '?') ;
printf ("|\n");
q3:
0 means: guess what is usually used (eg. INET + DGRAM -> TCP). As you specified raw the kernel is not able to choose a common protocol for the next layer.
IPPROTO_RAW should work (see comment of #nos)

Resources