Understanding set/getsockopt SO_SNDBUF size doubles - c

Hi I have the following program to check the send buffer size for a UDP socket. However, I the return value is a bit confusing to me. I use the following simple app:
#include <sys/socket.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int sockfd, sendbuff;
socklen_t optlen;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
printf("Error");
int res = 0;
// Get buffer size
optlen = sizeof(sendbuff);
res = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
if(res == -1)
printf("Error getsockopt one");
else
printf("send buffer size = %d\n", sendbuff);
// Set buffer size
sendbuff = 98304;
printf("sets the send buffer to %d\n", sendbuff);
res = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
if(res == -1)
printf("Error setsockopt");
// Get buffer size
optlen = sizeof(sendbuff);
res = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
if(res == -1)
printf("Error getsockopt two");
else
printf("send buffer size = %d\n", sendbuff);
return 0;
}
The output on my machine is:
send buffer size = 129024
sets the send buffer to 98304
new send buffer size = 196608
Can anybody clarify what I'm doing wrong here or how to interpret the output?

You're not doing anything wrong. Linux doubles the value (within the kernel) when you set it, and returns the doubled value when you query it. man 7 socket says:
[...]
SO_SNDBUF
Sets or gets the maximum socket send buffer in bytes. The ker-
nel doubles this value (to allow space for bookkeeping overhead)
when it is set using setsockopt(), and this doubled value is
returned by getsockopt(). The default value is set by the
wmem_default sysctl and the maximum allowed value is set by the
wmem_max sysctl. The minimum (doubled) value for this option is
2048.
[...]
NOTES
Linux assumes that half of the send/receive buffer is used for internal
kernel structures; thus the sysctls are twice what can be observed on
the wire.
[...]

Related

Sockets Programming Program received signal SIGSEGV, Segmentation fault

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.

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 Send And Receive Buffer

I tried to learn about the conception of Socket-Send(Receive)-Buffer.And I wrote these codes:
Client:
int client = socket(AF_INET, SOCK_STREAM, 0);
int s = getsockopt(client, SOL_SOCKET, SO_SNDBUF, &sendBuffSize, &len);
int status = connect(client, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
printf("The send buff size is : %d.\n", sendBuffSize);
char buf[100000];
int n, wn;
int fd = open("./1.txt", O_RDONLY);
while ((n = read(fd, buf, sizeof(buf))) > 0) {
wn = write(client, buf, n);
printf("Write %d bytes.\n", wn);
}
Server: I set the connected client as Non-block,and add this client into the epoll.Once the client sends data to the server, I put the main thread into sleep[ten seconds].
char buf[8192];
sleep(10);
int rn;
while ((rn = read(events[i].data.fd, buf, sizeof(buf))) > 0) {
printf("Read %d bytes.\n", rn);
}
The client send Buffer size is 16384 and the server receive Buffer size is 20000[setsockopt].
According to the book:The client calls the write function will block if the socket send buffer is full.
But I get the result[Client] :
Result
And the server :
Result
Questions:
Receive buffer size + Send buffer size < 100000; but why the write function do not block?
Why the server read 8192 + 6808 = 15000 bytes instead of read continuously 8192 bytes?
There is no evidence here that the client writes did not block. On the contrary, the fact that all the writes were 100,000 bytes except the last, when you ran out of input, shows that it must have blocked, to transfer all that data into a socket buffer that is smaller.
TCP segmentizes, and IP packetises, the data sent over the wire. You have no control over that process. In any case a read() can transfer any amount of bytes from 1 up to the count supplied, or zero upwards in non-blocking mode. It is a streaming protocol, not a messaging protocol. There is no other guarantee about how much any individual read() will return at a time.

read()/recv() successfully but buffer is unchanged and empty

I am writing a client to read the data sent back from a server over socket under TCP with c script on LINUX.
The server is running forever and I validate if I can get the reply with netcat localhost [PORT_NUMBER] already. The server is in LISTEN state when checking with netstat -nap
The recv() function returns expected number of bytes, but buffer becomes empty and strlen(buffer) is 0. I also try changing to read() which I did not expect a different result, and the same problem was shown.
This is the code.
#include <stdio.h>
#include <string.h> //strlen
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int socket_desc, msg_rep_size = 1200, msg_size = 100;
struct sockaddr_in server;
char message[msg_size], server_reply[msg_rep_size];
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
server.sin_addr.s_addr = inet_addr("0.0.0.0");
server.sin_family = AF_INET;
server.sin_port = htons(31114); // PORT_NUMBER
//Connect to remote server
if (connect(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
printf("connect error");
return 1;
}
printf("Connected");
while (1)
{
// send some data
bzero(message, msg_size);
strncpy(message, "REQUEST\n", msg_size);
if (send(socket_desc, message, msg_size, 0) < 0)
{
printf("Send failed");
return 1;
}
printf("Data Send\n");
// Receive a reply from the server
bzero(server_reply, msg_rep_size);
int read_result = recv(socket_desc, server_reply, msg_rep_size, 0);
if (read_result < 0)
{
printf("Receive failed\n");
return 1;
}
else
{
printf("Reply received\n");
printf("read_result: %d\n", read_result);
printf("strlen(server_reply): %d\n", (int)strlen(server_reply));
printf("Reply: %s\n", server_reply);
}
usleep(8);
}
return 0;
}
The printed result in bash is
Data send
Reply received
read_result: 1108
strlen(server_reply): 0
Reply:
The same result is shown if I change from
int read_result = recv(socket_desc, server_reply, msg_rep_size, 0);
to
int read_result = read(socket_desc, server_reply, msg_rep_size);
Thank you for your help. I am new to socket programming and could not track what is going on.
PS. The expected size of bytes from reply is 1108, which is correct. I intended to put maximum size as 1200 to confirm that correct number of byte is received.
PS2. Please feel free to also comment on the coding style of low-level c as well.
There is no evidence here of a problem, only bad code. If recv() returned 1088 it certainly transferred 1088 bytes into the buffer. Clearly the data received starts with a null byte. To print it correctly, use
printf("%.*s\n", read_result, server_reply);
NB:
'The expected size of bytes from reply is 1108, which is correct'. No it isn't. There is no 'expected size'. TCP is a streaming protocol. If recv() returns a positive number, the byte count transferred can be anything from 1 upwards to the buffer length supplied. You have to code a loop to be sure of getting exactly N bytes.
Before assuming it is positive, you must also check read_result for zero, which indicates that the peer has disconnected. Do not omit this step.
strlen(server_reply) is irrelevant. You don't know whether there is a trailing null at all. There could be no nulls at all, or several, including, as in this case, one right at the beginning.

How to solve: sending UDP packet using Sendto() got "message too long"

I want to use the sendto() API to send video and audio data through UDP packet. The sending buffer size I got using getsockopt() is 114688, however, sendto() returned -1 when the data packet less than 65536 not 114688. And the error message is Message too long.
When I used setsockopt() to adjust the sending buffer size as 200000, I used getsockopt() and found the sending buffer size was not 200000 but 262142. So I still got the same error when I sent data packet with a size bigger than 65536.
I am confused about this situation. I want to know what the reason is and how to solve this problem.
When I used FFMPEG library to send the video and audio packet, there is no error. So I am sure there is a solution for this problem and I missed something.
Is there anyone can help me about this problem? I really can not understand what the reason is.
The OS I used is ubuntu 11.04,I got the same results in ubuntu 11.10.
That is the code I used to create socket and configure the parameter:
unsigned char *output_buffer = (unsigned char*)av_malloc(IO_BUFFER_SIZE);
if (NULL == output_buffer) {
printf("Couldn't allocate input buffer.\n");
return NULL;
}
output_context_data_t *context_data = (output_context_data_t *)malloc(sizeof(output_context_data_t));
if (NULL == context_data) {
printf("Could not allocate output context data.\n");
av_free(output_buffer);
return NULL;
}
context_data->socket = socket(AF_INET, SOCK_DGRAM, 0);
if(context_data->socket < 0) {
printf("socket creating fail!\n");
return NULL;
}
context_data->socket_addr->sin_family = AF_INET;
context_data->socket_addr->sin_port = htons(output_port);
ret = inet_pton(AF_INET, output_ip, &(context_data->socket_addr->sin_addr));
if(0 == ret) {
printf("inet_pton fail!\n");
return NULL;
}
ret = setsockopt(context_data->socket, IPPROTO_IP, IP_MULTICAST_TTL,
&option_ttl, sizeof(int));
if(ret < 0) {
printf("ttl configuration fail!\n");
return NULL;
}
ret = setsockopt(context_data->socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if(ret < 0) {
printf("resue configuration fail!\n");
return NULL;
}
That is the code to send UDP packet:
int send_size = sendto(context_data->socket, buf, buf_size, 0,
(struct sockaddr *)context_data->socket_addr, sizeof(*context_data->socket_addr)));
//the video or audio data is in buf and its size is buf_size.
That is the code I used to get the sending buffer size:
int bufsize;
int size = sizeof(bufsize);
getsockopt(context_data->socket,SOL_SOCKET, SO_SNDBUF, &bufsize, &size);
That is the code I used to configure the sending buffer size:
tmp = 200000;
ret = setsockopt(context_data->socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
if(ret < 0) {
printf("sending buffer size configuration fail!\n");
return NULL;
}
You can not send messages (datagrams) larger than 2^16 65536 octets with UDP. The length field of a UDP packet is 16 bits. The buffer sizes you're requesting are not about the size for a packet, but how many octets the OS does buffer incoming and outgoing in total (spread over multiple packets). But a single packet can not get larger.
Per #datenwolf's answer, you simply can't send more than 64k in a single UDP datagram, as that limit is implicit in the two-byte length field in the protocol.
Furthermore, it's not actually a good idea to send even that much at once. You should limit your packets to the MTU on the path between the two ends (typically in the region of 1500 bytes or less) so that you don't get fragmentation in the IP layer.
Fragmentation is bad - ok?
Why not just call sendto several times, with an offset into the buffer?
int sendto_bigbuffer(int sock, const void *buffer, const size_t buflen, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
size_t sendlen = MIN(buflen, 1024);
size_t remlen = buflen;
const void *curpos = buffer;
while (remlen > 0)
{
ssize_t len = sendto(sock, curpos, sendlen, flags, dest_addr, addrlen);
if (len == -1)
return -1;
curpos += len;
remlen -= len;
sendlen = MIN(remlen, 1024);
}
return buflen;
}
Something like the above function will send the buffer 1024 bytes at a time.

Resources