How to turn off buffering on write() system call? - c

I used to think that write() system call is unbuffered and that fwrite and fread are used for buffered IO. However I wrote simple programs to establish that some buffering was still going on when using write(). I am using write() and read() on sockets. Due to buffering, it is possible for the client to lag behind while server keeps sending packets. I do not want that. I want that the client must consume the record before the server sends more records.
How can I make that happen without adding network load of acknowledgments etc !
I am using gcc on linux
server.c :
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/tcp.h>
int remote_rr_port=2000; // Server will send RR logs using connection on this port.
char const *remote_server_ip="127.0.0.1";
int connFD_rr;
static void startTcpServer(int *sd, const int port) {
*sd= socket(AF_INET, SOCK_STREAM, 0);
// Set socket option so that port can be reused
int enable = 1;
setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
struct sockaddr_in a;
memset(&a,0,sizeof(a));
a.sin_family = AF_INET;
a.sin_port = port;
a.sin_addr.s_addr = INADDR_ANY;
int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a));
listen(*sd,2);
}
// Wait for connection from client
static int getTcpConnection(int sd) {
char buf[100];
socklen_t len;
struct sockaddr_in clientAddress;
printf("\nWaiting for connection from remote client\n");
len = sizeof(clientAddress);
int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len);
setsockopt(connFD_rr, SOL_SOCKET, SO_SNDBUF, (int[]){0}, sizeof(int));
printf("\n Connection from : %s:%d\n",inet_ntop(AF_INET, &clientAddress.sin_addr, buf, sizeof(buf)),clientAddress.sin_port);
fflush(stdout);
return connFD;
}
FILE* rdrr_server_start(void) {
// Socket Descriptors for the two connections
int rr_sd;
int input_sd;
startTcpServer(&rr_sd, remote_rr_port);
connFD_rr = getTcpConnection(rr_sd);
return fdopen(connFD_rr, "w");
}
int main() {
int i = 0;
rdrr_server_start();
for(i=0;i<10000000; i++) {
write(connFD_rr, &i, sizeof (int));
printf("%d\n", i);
}
return 0;
}
client.c :
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/tcp.h>
int remote_rr_port=2000; // Server will send RR logs using connection on this port.
char const *remote_server_ip="127.0.0.1";
int connFD_rr;
FILE* rdrr_client_start(void) {
connFD_rr = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in a;
memset(&a,0,sizeof(a));
a.sin_family = AF_INET;
a.sin_port = remote_rr_port;
a.sin_addr.s_addr = inet_addr(remote_server_ip);
printf("\nConnecting to Server on RR port");
int CONNECT_TO_SERVER= connect(connFD_rr,(struct sockaddr *) &a, sizeof(a));
printf("\nConnected to server on RR port");
setsockopt(connFD_rr, SOL_SOCKET, SO_RCVBUF, (int[]){0}, sizeof(int));
return fdopen(connFD_rr, "r");
}
int main() {
int i = 0;
rdrr_client_start();
getrchar();
while(1) {
read(connFD_rr, &i, sizeof (int));
printf("%d\n", i);
}
return 0;
}

Perhaps what you mean is that you want to disable Nagle's Algorithm in which case the solution is:
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (int[]){1}, sizeof(int));
Edit: Hmm, it looks like you want more than this, and I doubt what you want is possible without designing your own protocol on top of UDP.
Edit 2: You may be able to get an effect similar to what you want by limiting the send and receive buffer sizes. The server (sender) should do:
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (int[]){YOUR_BUF_LIMIT}, sizeof(int));
and the client (receiver) should do:
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (int[]){YOUR_BUF_LIMIT}, sizeof(int));

Related

Sending a UDP broadcast is detected by TCPdump as leaving OpenWRT router, but not by Wireshark on the receiving computer

My network consists of the GL-MT300N-V2 router running this code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int sock;
if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
perror("socket : ");
return -1;
}
int broadcast = 1;
if( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) != 0 )
{
perror("setsockopt BROADCAST: ");
close(sock);
return -1;
}
char netif[] = "eth0";
if( setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, netif, sizeof(netif) )
{
perror("setsockopt BIND : ");
close(sock);
return -1;
};
char *ip = "255.255.255.255";
char * msg = "OOO"; //Actual code has 250 'O's to be visible in the dump
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons( 4444 );
inet_aton( ip, &si.sin_addr.s_addr );
/* send data */
for(int i = 0; i < 10000; i ++) //Used to spam for tcpdump
{
size_t nBytes = sendto(sock, msg, strlen(msg), 0,
(struct sockaddr*) &si, sizeof(si));
if(i % 1000 == 0)
{
printf("Sent msg: %s, %d bytes with socket %d to %s\n", msg, nBytes, sock, ip);
}
}
return 0;
}
The code successfully continually and rapidly sends packets. Said packets are easily visible in TCPdump. However, when I connect the router to a Windows 10 PC or laptop using ethernet, the computers are unable to detect the packets with Wireshark.
The sheer amount of packets is likely not the problem, as other code I have run sends similar amounts of packets, all of which are received.
Windows firewall has also been disabled, so the packet isn't being dropped there either.
It could be an interface optimization--drop it in hardware, so to speak (assuming port 0x4444 is not LISTENING--check netstat). For obvious reasons, you do not want to send all bcasts up the stack.

Invalid Argument from sendto() Socket Program in C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm trying to make a simple client-server API to be used for two of my machines. I made this simple program that uses the functions I made to test it. For some reason my client sends a message just fine, but my server can't (however, it receives the message from the client).
Server side output:
host name: my_host
Our port number is: 34440
Client msg: Client msg
Send failed: Invalid argument
Message from Server sent to Client
Client side output:
Connection established with server...
Message from Client sent to Server
Server side:
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include "my_socket.h"
int main() {
server_init();
char *msg = "Server msg";
char buffer[100];
int n = read_from_client((char *)buffer);
buffer[n] = '\0';
printf("Client msg: %s\n", buffer);
write_to_client((char *)msg);
printf("Message from Server sent to Client \n");
return 0;
}
Client Side:
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include "my_socket.h"
int main() {
client_init();
char *msg = "Client msg";
char buffer[100];
write_to_server((char*)msg);
printf("Message from Client sent to Server \n");
int n = read_from_server((char *)buffer);
buffer[n] = '\0';
printf("Server msg: %s\n", buffer);
close_socket();
return 0;
}
my_socket.c:
#include "my_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
int sockfd1;
int sockfd2;
int MAX_BUFF = 1024;
struct sockaddr_in server;
struct sockaddr_in client;
struct hostent *host;
ssize_t write_to_server(const void *buffer){
int bytes_sent, server_size = sizeof(server), buf_len = strlen(buffer);
if ((bytes_sent = sendto(sockfd2, buffer, buf_len, 0,
(const struct sockaddr *)&server, server_size)) < 0){
perror("Send failed");
}
return bytes_sent;
}
ssize_t write_to_client(const void *buffer){
int bytes_sent, client_size = sizeof(client), buf_len = strlen(buffer);
if ((bytes_sent = sendto(sockfd1, buffer, buf_len, 0,
(const struct sockaddr *)&client, client_size)) < 0){
perror("Send failed");
}
return bytes_sent;
}
int read_from_server(void *buffer){
int bytes_rcv, len;
if ((bytes_rcv = recvfrom(sockfd2, buffer, MAX_BUFF, MSG_WAITALL,
(struct sockaddr *)&server, &len)) < 0){
perror("Read failed");
}
return bytes_rcv;
}
int read_from_client(void *buffer){
int bytes_rcv, len;
if ((bytes_rcv = recvfrom(sockfd1, buffer, MAX_BUFF, MSG_WAITALL,
(struct sockaddr *)&client, &len)) < 0){
perror("Read failed");
}
return bytes_rcv;
}
void close_socket() {
close(sockfd1);
close(sockfd2);
}
void server_init(){
if ( (sockfd1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
}
char name[1024];
name[1023] = '\0';
gethostname(name, 1023);
printf("host name: %s \n", name);
host = gethostbyname("my_host");
if(host == NULL){
perror("Host is null");
exit(0);
}
bzero((char *)&server, sizeof(server));
bzero((char *)&client, sizeof(client));
server.sin_family = AF_INET;
bcopy((char *)host->h_addr,
(char *)&server.sin_addr.s_addr, host->h_length);
//server.sin_port = 0;
server.sin_port = htons(34440);
if ( (bind(sockfd1, (struct sockaddr *)&server, sizeof(server) ) ) < 0 ){
perror("bind failed");
}
socklen_t len = sizeof(server);
if (getsockname(sockfd1, (struct sockaddr *)&server, &len) == -1){
perror("getsockname");
}else{
printf("Our port number is: %d\n", ntohs(server.sin_port));
}
}
void client_init(){
if ( (sockfd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
}
host = gethostbyname("my_host");
if(host == NULL){
perror("Host is null");
exit(0);
}
bzero((char *)&server, sizeof(server));
server.sin_family = AF_INET;
bcopy((char *)host->h_addr,
(char *)&server.sin_addr.s_addr, host->h_length);
//server.sin_port = 0;
server.sin_port = htons(34440);
if(connect(sockfd2, (struct sockaddr *)&server, sizeof(server)) == 0){
printf("Connection established with server...\n");
}
}
my_socket.h:
#ifndef MY_SOCKET
#define MY_SOCKET
#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>
#include <netdb.h>
extern int sockfd1;
extern int sockfd2;
extern int MAX_BUFF;
extern struct sockaddr_in server;
extern struct sockaddr_in client;
extern struct hostent *host;
// Send a message over the socket
ssize_t write_to_server(const void *buffer);
ssize_t write_to_client(const void *buffer);
// Blocks until told it's ready; receives bytes from socket
int read_from_server(void *buffer);
int read_from_client(void *buffer);
// Close the socket
void close_socket();
void server_init();
void client_init();
#endif
Any advice or criticism is welcome. Thanks in advance.
At least one issue is that you are not initializing the len variable in read_from_client. The manual page for recvfrom says, in part (emphasis added):
... addrlen is a value-result argument. Before the call, it should be initialized to the size of the buffer associated with src_addr. Upon return, addrlen is updated to contain the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
That means that, as an uninitialized stack variable, len has an indeterminate value. Probably zero, but at least something smaller than sizeof(struct sockaddr_in). As a result, client is not getting filled in correctly by the recvfrom.
Just before the recvfrom, you should initialize it with:
len = sizeof(client);
On the client side, write_to_server and read_from_server need not use recvfrom and sendto as you have already done a connect on the socket. They can simply use recv and send since the remote socket endpoint is already established by the connect. I believe the address is simply ignored for a connected socket, but I cannot find where that is documented right now.
(In any case, if you do continue to use recvfrom on the client side, you should make the same len initialization there.)

How to catch all udp messages like Wireshark without drops?

I have two programs udp sender and consumer on localhost. Sender generates four byte int messages at top speed, but the consumer does not get all of them. Consumer last line on stdout is
1484444 1999999
Wireshark intercepts all packages and slowly processes them all. How can I get the same behavior in a C program?
// sender.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main()
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in dest;
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(40500);
inet_aton("127.0.0.1", &dest.sin_addr);
int i;
for (i = 0; i < 2000000; ++i) {
sendto(sock, &i, sizeof(i), 0, (const struct sockaddr*)&dest, sizeof(dest));
}
}
// consumer.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <stdio.h>
int main()
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in dest;
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(40500);
inet_aton("127.0.0.1", &dest.sin_addr);
bind(sock, (const struct sockaddr*)&dest, sizeof(dest));
int i;
int buf;
for (i = 0; i < 2000000; ++i) {
recv(sock, &buf, sizeof(buf), 0);
printf("%d %d\n", i, buf);
}
}
I think your problem is the server side process slower than the
sender side.If the receive socket buffer of the server is full,
then the extra packets delivered by the kernel will be droped.
To improve the performance, I think there are several things you
can do:
1.Increase the server side receive buffer.
2.Try use batch send and receive interfaces(eg. sendmmsg(), recvmmsg()).
This will reduce the overhead of system call.
3.Don't call printf() everytime you receive a buffer of data.
It is time consuming.

how get socket port number from an accept call (C UNIX)

i've done a simple client/server program where the server wait for an external connection and return the connection-socket if the port number of the client is in the range of [1025-2048] otherwise return -1. The problem is that when i get the port number by the client adress (which should be stored in the sockaddr structure) it says me that the client port number is zero, but in the client program i've set the client portnumber to 1999.
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int function(int fd_socket) {
int fd_socket_acc;
int len;
int port;
struct sockaddr_in client_addr;
puts("WAITING FOR CLIENT...");
fd_socket_acc = accept(fd_socket, (struct sockaddr*)&client_addr, &len);
puts("CONNECTION DONE.");
port = ntohs (client_addr.sin_port);
printf("client port number: %d \n", port);
if (port >= 1024 && port <= 2048) {
close (fd_socket_acc);
return fd_socket_acc;
}
else {
close(fd_socket_acc);
return -1;
}
}
int main(int argc, char *argv[]) {
int fd_socket;
struct sockaddr_in local_addr;
fd_socket = socket(AF_INET, SOCK_STREAM, 0);
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(1887);
local_addr.sin_addr.s_addr = INADDR_ANY;
bind(fd_socket, (struct sockaddr*)&local_addr, sizeof(local_addr));
listen(fd_socket, 3);
function(fd_socket);
//close(fd_socket);
}
CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int fd_socket;
struct sockaddr_in local_addr;
struct sockaddr_in server_addr;
struct hostent *hp;
fd_socket = socket(AF_INET, SOCK_STREAM, 0);
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(1999);
local_addr.sin_addr.s_addr = INADDR_ANY;
bind(fd_socket, (struct sockaddr*)&local_addr, sizeof(local_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1887);
//hostname is "ubuntu"
hp = gethostbyname("ubuntu");
bcopy(hp->h_addr, &server_addr.sin_addr, 4);
printf("%d \n", ntohs(local_addr.sin_port));
connect(fd_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
wait(2);
close(fd_socket);
}
If i get the port number in client with a printf("%d", ntohs(local_addr.sin_port)) it stamps correctly 1999, but if i get the port number of client in server with printf("%d", ntohs(client_addr.sin_port)) it stamps 0. Why?
thanks in advance!
In order to obtain the client port number in client_addr through accept you have to tell accept how big that buffer is by setting
socklen_t len = sizeof(client_addr);
You can alternatively retrieve it by calling afterwards
len = sizeof(client_addr);
getpeername(fd_socket_acc, (struct sockaddr*)&client_addr, &len);
Maybe because you do not set the variable len to anything, and I suspect that your compiler sets it to 0.
What happens is that you try to accept with an undefined len size.
Adding len=sizeof( struct sockaddr_in ); before making a call to accept would help to fill the passed client_addr correctly.

Chat client in c

Problem:
I need some help with an error in my code. The chat client works when I only have one client running but if i use more clients. Only the last client messages will show up on my server. my client.c seems to work since it is sending but for some reason recv() is not getting the previous client send().
How code works:
I set up my server and spawn a new thread whenever a new client connects. the thread will handle the messages i get form the client and print it on the server screen.
Code:
CLIENT.C
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char ** argv){
//get port
//int port = atoi(argv[1]);
int server_port = atoi(argv[1]);
char * name =argv[2];
int namelength = strlen(name);
//set up server adress and socket
int sock = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(server_port);
//connect
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connect failed");
exit(1);
}
//set up client name
char * buff = malloc(5000*sizeof(char));
//get the chatting
//char * other_message = malloc(5000*sizeof(char));
while(1){
printf("ENTER MESSAGE:\n");
char message[5000];
strcpy(message, name);
strcat(message,": ");
printf("%s", message);
scanf("%[^\n]",buff);
getchar();
strcat(message,buff);
int sent = send(sock , message , strlen(message) , MSG_DONTWAIT );
if (sent == -1)
perror("Send error: ");
else
printf("Sent bytes: %d\n", sent);
}
return 0;
}
SERVER.C
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
pthread_t * threads = NULL;
int * client_fd = NULL;
int num_clients;
int thread_num;
void * client_handler(void * cl)
{
int * client = (int *)cl;
char * message = malloc(5000*sizeof(char));
printf("Connected: %d\n",*client);
int byte=1;
//recieve the message from clients
while(1)
{
byte=recv(*client, message , 5000 , 0);
if(byte< 0)
break;
//send message to all other clients
printf("%s\n",message);
printf("Recieved bytes:%d\n",byte);
memset(message, 0, 5000);
/*for(i=0;i<num_clients;i++)
if(client_fd[i]!=*client)
send(*client , message , strlen(message),0);*/
}
printf("finished: %d\n",*client);
return NULL;
}
int main(int argc, char ** argv)
{
//get the port
int port = atoi(argv[1]);
//set up socket
int socket_fd = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in server,client;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
//bind
if(bind(socket_fd, (struct sockaddr*)&server,sizeof(server)) < 0 ){
perror("binding error\n");
exit(1);
}
//listen
if( listen(socket_fd, 10) <0){
perror("binding error\n");
exit(1);
}
//accept incoming connectionns
threads = malloc(10*sizeof(pthread_t));
client_fd = malloc(10*sizeof(int));
int i=0;
int c = sizeof(struct sockaddr_in);
while(1)
{
int c_fd = accept(socket_fd,(struct sockaddr *)&client, (socklen_t*)&c);
if(c_fd < 0)
printf("error");
client_fd[i]=c_fd;
pthread_create(&threads[i],NULL,client_handler,(void *)(&c_fd));
i++;
num_clients=i;
}
return 0;
}
Sending C-style strings with strlen(). Does not send the terminating null. Use strlen()+1
Ignoring the value returned by recv(). TCP is a streaming protocol that only transfers bytes/octets. It does not transfer anything more complex. recv() may return one byte of your chat line, all of your chat line, or anything in between. To transfer any message more complex than one byte, you need a protocol and you must handle it. Yours is 'chat lines are null-terminated strings', so you need to call recv() in a loop and, using the returned value, concatenate the bytes received until the null arrives.
Trying to printf non-strings with "%s". You must not attempt to print out the received data until you are sure that a null has been received.

Resources