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.
Related
I am trying to create a file transfer program using pthread.h in regards to sockets programming using C.
Both the client and the server source code are implemented but when I run the program it reports "Segmentation fault (core dumped)".
I tried running the program with gdb and it gives me the following error when I input a given file for transfer from the client-side.
Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2_unaligned ()
at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298
298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
Here is the client source code:
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_PATH_SIZE 1024
void find_file_name(char *name, char *path);
int main()
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htons(INADDR_ANY);
client_addr.sin_port = htons(0);
int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
}
else {
perror("Create Socket Done:");
}
if (-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
{
perror("Client Bind Failed:");
exit(1);
}
else {
perror("Client Bind Success:");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Declare a socket address structure on the server side, and initialize it with the IP address and port on the server side for subsequent connections
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
//Convert the dotted decimal string into a network byte order binary value. This function can handle both IPv4 and IPv6 addresses.
// The first parameter can be AF_INET or AF_INET6:
// The second parameter is a pointer to a dotted decimal string:
// The third parameter is a pointer to the binary value of the converted network byte order.
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)
{
perror("Server IP Address Error:");
exit(1);
}
else {
perror("Server IP Address Success:");
}
server_addr.sin_port = htons(SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
// int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// sockfd: the first parameter is the socket descriptor of the client
// addr: the local address of the current client, a variable of type struct sockaddr_un, a variable of type struct sockaddr_in in different hosts,
// addrlen: indicates the byte length of the local address
// Return value: success flag
if (connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
perror("Can Not Connect To Server IP:");
exit(0);
}
else {
perror("Connected to the Server IP:");
}
char file_path[FILE_PATH_SIZE + 1];
bzero(file_path, FILE_PATH_SIZE + 1);
printf("Input the File Path on Server:\t");
scanf("%s", file_path);
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strncpy(buffer, file_path, strlen(file_path)>BUFFER_SIZE ? BUFFER_SIZE : strlen(file_path));
//ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//socket: If it is a server, it is the return value of accpet() function, the client is the first parameter in connect() function
// buffer: data written or read
// len: size of data written or read
if (send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Send File Name Failed:");
exit(1);
}
//Convert the target path to a local storage path
char save_path[FILE_PATH_SIZE + 1] = {"/home/madaskalas/Desktop/sockets/pthread/client_files"};
find_file_name(file_path, save_path);
//Try to open the file
FILE *fp = fopen(save_path, "w");
if (NULL == fp)
{
printf("File:\t%s Can Not Open To Write\n", save_path);
exit(1);
}
// Receive data from the server to the buffer
// Each time a piece of data is received, it will be written to the file, looping until the file is received and written
bzero(buffer, BUFFER_SIZE);
int length = 0;
while ((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
{
if (fwrite(buffer, sizeof(char), length, fp) < length)
{
printf("File:\t%s Write Failed\n", save_path);
break;
}
bzero(buffer, BUFFER_SIZE);
}
// After receiving successfully, close the file and close the socket
printf("Receive File:\t%s From Server IP Successful!\n",save_path);
// close(fp);
close(client_socket_fd);
return 0;
}
void find_file_name(char *name, char *path)
{
char *name_start = NULL;
int sep = '/';
if (NULL == name) {
printf("the path name is NULL\n");
// return NULL;
}
name_start = strrchr(name, sep);
if (NULL == name_start)
{
strcat(path, name_start);
}
else
strcat(path, name_start + 1);
}
Here is the server source code:
#include<stdlib.h>
#include<pthread.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<arpa/inet.h>
#include <unistd.h>
#define SERVER_PORT 8000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 1024
static void Data_handle(void * sock_fd);
int main(void)
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Declare and initialize a server-side socket address structure, socketaddr_in is the address form of the socket in the internet environment
//sockaddr_in (defined in netinet/in.h):
// struct sockaddr_in {
// short int sin_family; /* Address family */
// unsigned short int sin_port; /* Port number */
// struct in_addr sin_addr; /* Internet address */
// unsigned char sin_zero[8]; /* Same size as struct sockaddr */
//};
//struct in_addr {unsigned long s_addr;};
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
//Sa_family: It is an address family, also a masterpiece, a protocol family, generally in the form of "AF_XXX", commonly used are
//AF_INET Arpa (TCP/IP) network communication protocol
//AF_UNIX UNIX domain protocol (file system socket)
//AF_ISO ISO standard protocol
//AF_NS Xerox Network System Agreement
//AF_IPX Novell IPX protocol
//AF_APPLETALK Appletalk DDS
server_addr.sin_family = AF_INET;
//htons is to convert integer variables from host byte order to network byte order, that is, the integer storage method in the address space becomes the high-order byte and is stored at the low address of the memory.
//INADDR_ANY: 0.0.0.0, which refers to the meaning of this machine, that is, it means all the IP of this machine, monitor all the network cards of this machine
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create socket, if successful, return socket descriptor
//1, domain: the protocol domain, also known as the protocol family (family). AF_INET: TCP/IP protocol cluster
//2, type: Specify the socket type. SOCK_STREAM (commonly used) byte stream socket
//3, protocol: As the name implies, it is to specify the protocol. 0: IPPROTO_TCP TCP transmission protocol
int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
if(server_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
}
else {
perror("Create Socket Done:");
}
//int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
//sock: The socket that will be set or get options. level: The protocol layer where the option is located.
//optname: The name of the option to be accessed. optval: For getsockopt(), points to the buffer that returns the option value. optlen: The maximum length of the option value when used as an entry parameter.
// Let SO_REUSEADD==true allow the socket to be bound to an address already in use (see bind()).
int opt = 1;
setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//bind binds socket and socket address structure
//The three parameters are: socket descriptor, protocol address, and the length of the address
if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
{
perror("Server Bind Failed:");
exit(1);
}
else {
perror("Server Bind Success:");
}
//sockfd: The first parameter is the socket descriptor to be monitored
//backlog: The second parameter is the maximum number of connections that the corresponding socket can queue
//The socket created by the socket() function is an active type by default, and the listen function changes the socket to a passive type, waiting for the client's connection request.
if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
{
perror("Server Listen Failed:");
exit(1);
}
printf("Socket Listen Successful! Begin to listen!\n");
///////////////////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
// Define the client's socket address structure
struct sockaddr_in client_addr;
socklen_t client_addr_length = sizeof(client_addr);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//sockfd: The first parameter is the socket descriptor of the server
//addr:, the second parameter is a pointer to struct sockaddr *, used to return the client's protocol address
//addrlen: The third parameter is the length of the protocol address
//Return value: If accpet succeeds, the return value is a brand new description word automatically generated by the kernel, which represents the TCP connection with the returning client.
// Accept the connection request and return a new socket (descriptor). This new socket is used to communicate with the connected client
// The accept function will write the client information to client_addr
int session_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
if(session_fd < 0)
{
perror("Server Accept Failed:");
// break;
}
else {
perror("Server Accept Success:");
}
char client_addr_res[20];
//char *ptr=inet_ntop(AF_INET, &client_addr.sin_addr, client_addr_res, strlen(client_addr_res));
printf("Get Connected with Client:%s ,Opening a new Thread...\n",inet_ntoa(client_addr.sin_addr) );
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&session_fd)) == -1)
{
fprintf(stderr, "pthread_create error!\n");
break; //break while loop
}
}
// Close the socket for monitoring
close(server_socket_fd);
return 0;
}
static void Data_handle(void * fd)
{
int session_fd = *((int *)fd);
// The recv function reads the data into the byte stream through the description word and stores it in the address string
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
if (recv(session_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Server Recieve Data Failed:");
}
char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, FILE_NAME_MAX_SIZE + 1);
strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));
printf("Received Filename Successful\n");
// Open the file to read the data and transfer it to the connected client by the file name
FILE *fp = fopen(file_name, "r");
if (NULL == fp)
{
printf("File:%s Not Found\n", file_name);
}
else
{
bzero(buffer, BUFFER_SIZE);//Empty the buffer
int length = 0;
//Read one BUFFER_SIZE data at a time and send it to the client
while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
//ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//socket: If it is a server, it is the return value of the accpet() function, and the client is the first parameter in the connect() function
// buffer: data written or read
// len: size of data written or read
if (send(session_fd, buffer, length, 0) < 0)
{
printf("Send File:%s Failed./n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
}
fclose(fp);
printf("Send File:%s To Client Successful!\n", file_name);
}
// int close(int fd) fd: the first parameter of the client's connect() function, the return value of the server's accept()
close(session_fd);
pthread_exit(NULL); //terminate calling thread!
}
Compilation:
gcc -o pthread_client pthread_client.c
gcc -o pthread_server pthread_server.c
I compiled with -g and then use gdb with bt and it produces the following error.
Program received signal SIGSEGV, Segmentation fault. __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory. (gdb) bt #0 __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 #1 0x00005555555558b8 in find_file_name (name=0x7fffffffd440 "b.txt", path=0x7fffffffd850 "/home/madaskalas/Desktop/sockets/pthread/client_files") at pthread_client.c:138 #2 0x00005555555556fe in main () at pthread_client.c:96 –
Any help or guidance is greatly appreciated!
Do not cast to/from void*. It happens implicitly.
void Data_handle(void*); pthread_create(..., (void *)(&Data_handle), ...) is plain invalid. Data_handle should return a void*, not void. Calling a void (void*) function via void *(*)(void*) function pointer is invalid.
in server, int session_fd is a local variable inside while(1) block, yet it is passed by pointer to a thread pthread_create(, ... &session_fd) and then thread *((int *)fd); dereferences it. There is a race condition, that session_fd stops existing on the end of loop. Either use dynamic allocation, create a synchronization point to make sure it is dereferenced, or just cast it to/from uintptr_t and pass by value as the void* pointer.
why that bzero all the time? Remove all the calls to bzero maybe except for sockaddr_in initialization. Consider using = {0} there anyway.
strncpy(dest, src, strlen(src) > sizeof(dest) ? sizeof(dest) : strlen(src)) - the strlen(src) > .... is just pointless, cause then the string will not be zero terminated. Also, strncpy does copy up until zero terminating character anyway, it's not memcpy, so why check if yourself anyway. Research strlcpy and strncpy difference, and just use strlcpy(dest, src, sizeof(dest)) to copy a string anyway. Read NOTES section in strncpy man page.
if (NULL == name_start) { strcat(path, name_start); - it's invalid to copy from NULL...
You use strange additional braces in if (-1 == (function())). The ))) are very hard for humans to read in my experience. Consider using if (-1 == function()).
Instead of *((int *)fd) just *(int *)fd.
Try not to do self-explanatory comments.
Overall your code is bad and is filled with bugs and edge cases. Consider rewriting it from scratch and re-studying your material. Interest yourself in helpful code helpers - like -Wall -Wextra -fsanitize=address warnings gcc options, code linters and formatters and valgrind.
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.
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)
I wrote the code in order to handle receiving UDP packets. The packets are all same length(120 bytes), and about 1,000 packets are coming in every second. Simply, my code is like this.
int sock = -1;
int flag = 0;
int nRead = 0;
#define LOCAL_BUFF_SIZE (8192)
char buff[LOCAL_BUFF_SIZE];
struct sockaddr_in sockAddr;
memset((void *)&sockAddr, 0x00, sizeof(struct sockaddr_in));
if((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
/* Print error and terminate */
}
/* Make it non-blocking */
flag = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flag | O_NONBLOCK );
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(portNum);
sockAddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (struct sockaddr *)&sockAddr, sizeof (sockAddr)) < 0)
{
/* Print error and terminate */
}
while(...)
{
nRead = recv(sock, buff, LOCAL_BUFF_SIZE, 0);
if(nBytes > 0)
{
/* Process the data */
}
else
{
/* If it's error, handle error */
}
}
When I wrote this code, I expect that recv() function returns every bytes in the UDP socket buffer at that moment, but, it seems that it only returns one packet(120 byte) every time even though there are more bytes in the buffer. So now I encountered with packet loss. I know that there are many other ways to solve this problem, but, for now reading all existent bytes in the UDP buffer at once is the easiest way for me. So, is there any way to read all bytes in the UDP buffer at once?
Thanks in advance
UDP is a message oriented protocol, therefore, you are getting single message in one recv operation. You can possible use recvmmsg() system call to receive multiple messages in a single call.
it seems that when i use send() function (in a TCP file transfer program) like this
while((count = recv(socketConnection, buff, 100000, 0))>0)
myfile.write(buff,count);
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data but in a similar program for a UDP program
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
the recvfrom() function just blocks and does not exit the loop for some reason, as far as i know both recv() and recvfrom() are blocking right?? Then why the difference. Does it have something to do with the functions or just the nature of TCP,UDP(which i guess is not a reason)??
P.S. Please help me understand this guys, I'm a newbie to socket programming and networking.
EDIT: full server program for both TCP and UDP
UDP server (with recvfrom() )
int i=0;
int sockfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
char mesg[1024];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
ofstream myfile;
// fcntl(sockfd,F_SETFL,O_NONBLOCK);
myfile.open("2gb",ios::out);
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
TCP (recv() ) server program
struct sockaddr_in socketInfo;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
struct hostent *hPtr;
int socketHandle;
int portNumber = 8070;
//queue<char*> my_queue;
bzero(&socketInfo, sizeof(sockaddr_in)); // Clear structure memory
gethostname(sysHost, MAXHOSTNAME); // Get the name of this computer we are running on
if((hPtr = gethostbyname(sysHost)) == NULL)
{
cerr << "System hostname misconfigured." << endl;
exit(EXIT_FAILURE);
}
if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(socketHandle);
exit(EXIT_FAILURE);
}
// std::cout<<"hi starting server";
socklen_t optlen;
int rcvbuff=262144;
optlen = sizeof(rcvbuff);
socketInfo.sin_family = AF_INET;
socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
socketInfo.sin_port = htons(portNumber); // Set port number
if( bind(socketHandle, (struct sockaddr *) &socketInfo, sizeof(socketInfo)) < 0)
{
close(socketHandle);
perror("bind");
exit(EXIT_FAILURE);
}
listen(socketHandle, 1);
int socketConnection;
if( (socketConnection = accept(socketHandle, NULL, NULL)) < 0)
{
exit(EXIT_FAILURE);
}
close(socketHandle);
time_start(boost::posix_time::microsec_clock::local_time());
int rc = 0; // Actual number of bytes read
int count=0;
char *buff;
int a=100000;
buff=new char[a];
ofstream myfile;
myfile.open("345kb.doc",ios::out|ios::app);
if(myfile.is_open())
{
long i=0;
while((count = recv(socketConnection, buff, 100000, 0))>0)
{
myfile.write(buff,count);
}}
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data
recv() on a TCP connection returns 0 when the sending side has closed the connection and this is the condition for your loop to terminate.
for a UDP program the recvfrom() function just blocks and does not exit the loop for some reason,
Because UDP is a connection-less protocol hence there is no special return code from recv() for a closed UDP connection. Unless someone sends you a 0-length datagram.
recv() will end the loop because at the other side the socket is closed, so recv() will return 0 (socket gracefully closed) whereas, recvfrom that does not have that signal, it does not know about closing, because it's an unconnected socket. It's stay there until it receives a packet or timeout, with UDP you need a way to tell that the communication is over (finish).