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.
Related
I wrote a server program and a client program that communicate with sockets on linux ubuntu. The client program outputs Received: 艎��
This my server code:
/*** tcp_server.c ***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
int sock_fd, new_fd, bytes;
struct sockaddr_in seraddr, cliaddr;
char data[1024];
socklen_t cli_addr_size;
cli_addr_size = sizeof(cliaddr);
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY : It received Network Interface that connected server defined interface, htonl :
seraddr.sin_port = htons(5050);
bind(sock_fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
listen(sock_fd, 10);
while (1) {
new_fd = accept(sock_fd, (struct sockaddr *)&cliaddr, &cli_addr_size);
bytes = recv(new_fd, data, 1024, 0);
send(new_fd, data, bytes, 0);
close(new_fd);
}
close(sock_fd);
}
My client code is:
/*** tcp_client.c ***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(int argc, char *argv[]) {
int sock_fd, bytes;
struct sockaddr_in ser_addr;
char *snddata, rcvdata[1024];
snddata = argv[2];
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&ser_addr, 0,sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = inet_addr(argv[1]); // INADDR_ANY : It received Network Interface that connected server defined interface, htonl :
ser_addr.sin_port = htons(5050);
connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
send(sock_fd, snddata, strlen(snddata), 0);
printf("Received: ");
bytes = recv(sock_fd, rcvdata, 1024, 0);
rcvdata[bytes] = '\0';
printf("%s\n", rcvdata);
close(sock_fd);
}
First I got an error for argument 3 of accept, then I changed
new_fd = accept(sock_fd, (struct sockaddr *)&cliaddr, sizeof(cliaddr);
But It still produces this strange word.
Try to change your send() and receive() functions so that you have full control over how much and which byte you send from the buffer (data[1024]) like in this thread : C socket: recv and send all data and also see Beej's Guide to Network Programming (http://beej.us/guide/bgnet/)
Also make sure that you initialize your data buffers:
data[1024] = "";
rcvdata[1024] = "";
or
data[1024];
data[0] = '\0';
rcvdata[1024];
rcvdata[0] = '\0';
, background is in this thread : Why I am getting this unusually symbols by printing char string
I'm currently using this as a learning example:
https://os.mbed.com/teams/mqtt/code/MQTTPacket/file/aedcaf7984d5/samples/simple-publish.txt/
However, some of the code is specific to whatever embedded system the example is using.
What I got so far is:
#include "hw_util.h"
#include "MQTTPacket.h"
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
int main (void) {
int i;
float temperatura;
unsigned char buffer[50];
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
int rc = 0;
char buf[200];
int buflen = sizeof(buf);
MQTTString topicString = MQTTString_initializer;
char* payload = "I'm Alive";
int payloadlen = strlen(payload);
int len = 0;
data.clientID.cstring = "Testing";
data.keepAliveInterval = 20;
data.cleansession=1;
data.MQTTVersion=3;
len = MQTTSerialize_connect(buf,buflen,&data);
topicString.cstring="SampleTopic";
len += MQTTSerialize_publish(buf + len, buflen - len, 0, 0, 0, 0, topicString, payload, payloadlen);
printf("Hello world");
rc = 0;
while(1)
{
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
}
}
I downloaded HiveMQ, which is a Broker and it's running:
2018-03-05 19:28:08,195 INFO - Starting TCP listener on address 0.0.0.0 and port 1883
Now what I want to do, is send something like "Hello World" to this Broker or to Putty or something that would display the entire MQTT payload. How does C handle this? The documentation helped me understand what's going on but didnt really help me write C code, since I am still very new to it.
This took a while but I figured it out. There are still plenty of kinks to work out, but at least it sends an MQTT(Wireshark approved) packet to localhost.
Create an MQTT packet using this library: https://os.mbed.com/teams/mqtt/code/MQTTPacket/
Using this code:
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
char buf[200];
MQTTString topicString = MQTTString_initializer;
data.clientID.cstring = "TESTIRAM";
data.keepAliveInterval = 20;
data.cleansession=1;
data.MQTTVersion=3;
len = MQTTSerialize_connect(buf,buflen,&data);
topicString.cstring="ka";
len += MQTTSerialize_publish(buf + len, buflen - len, 0, 0, 0, 0,
topicString, payload, payloadlen);
Set up a socket:
This code worked for me, but its LINUX SPECIFIC!
#include "hw_util.h"
#include "MQTTPacket.h"
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
char buf[200];
int mysock=0;
char *host = "127.0.0.1";
int port = 1883;
mysock = socket(AF_INET, SOCK_STREAM, 0);
AF_INET specifies IPv4 and SOCK_STREAM specifies TCP.
Connect to socket
Use this:
struct sockaddr_in cliaddr;
int rc = 0;
//initialize the host address
memset(&cliaddr, 0, sizeof(cliaddr));
//specify IPv4 protocol
/*following includes are necessary for this:#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>*/
cliaddr.sin_family = AF_INET;
//intialize the IP address of the host as "127.0.0.1"
cliaddr.sin_addr.s_addr = inet_addr(host);
//initialize the port, 1883
cliaddr.sin_port = htons(port);
//client has no bind
//socket()>connect()->send()<->recv()->close
int statusConn = connect(mysock,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
if(statusConn=0){
printf("Success!");
}
if(statusConn=-1){
printf("Connect unsuccessful!\n");
Send over socket!
This should work:
while(1)
{
printf("Sending to hostname %s port %d\n", host, port);
//infinite loop, sending packets to the specified ASOCKET
//after sending sleep for 10 seconds
//sleep uses unistd.h
printf("Sent packets: ");
int countSend = send(mysock ,buf,buflen,0);
printf("%d",countSend);
printf("\n");
sleep(10);
}
Some of the imports might be useless and some might be Linux specific. I'm moving onto AT commands so most of the issues in this code won't transfer to the new codebase.
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.
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.
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));