So I'm doing some benchmarking of TCP to study the impact of the amount of data transferred per connection over the resulting bandwidth. So I wrote a server and a client in C to measure what I need. I then used a Python script to run the experiments many times (To have a precision of +/- 1% I ran my test for 100s. For each point of data I ran the experiment 33 times to get a decent average.), with different inputs, and to gather the results.
The results I get seem about right (I can even observe the expected plateau at higher amounts of data transferred per connection) with the exception that the bandwidth is only 10% of what it should be...
Because I only have access to one computer to run this benchmark, I'm doing the tests on localhost, but that shouldn't be an issue.
Here are my results:
As you can see, it seems the best bandwidth I can get is a bit more than 300 MB/s... But if I run a bandwidth test with iperf (I made sure to use the same TCP window size), on localhost I get a bandwidth of about 3 GB/s.
Here is the code of my client:
int main(int argc, char const *argv[])
{
unsigned int size;
unsigned int timeout;
int sockfd;
struct sockaddr_in server_addr;
if(argc < 4 || argc > 5 ){
usage();
exit(1);
}
const char * ip = "127.0.0.1";
ip = argv[3];
int port = PORT;
if(argc == 5) {
port = atoi(argv[4]);
}
size = atoi(argv[1]);
timeout = atoi(argv[2]);
unsigned int count = 0;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
while((end.tv_sec - start.tv_sec) < timeout) {
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("Could not create socket\n");
exit(0);
}
bzero(&server_addr, sizeof(server_addr));
// assign IP, PORT of the server
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
// connect the client socket to server socket
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
perror("connection with the server failed");
exit(1);
}
unsigned int nread = 0;
unsigned int nreadcum = 0;
char* buf = malloc(size);
char* bufbuf = buf;
while(nreadcum < size){
nread = read(sockfd, bufbuf, size-nreadcum);
nreadcum += nread;
bufbuf+=nread;
}
// close connection
close(sockfd);
count++;
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
free(buf);
}
uint64_t sec = (end.tv_sec - start.tv_sec);
double bandwidth = (count*size)/sec;
printf("%u,%lf,%u,%lu\n", size, bandwidth, count, sec);
return 0;
}
And here is the code of my server:
int serv_sock_fd;
int main(int argc, char const *argv[])
{
int size;
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
int bound_port;
if(argc != 2){
usage();
exit(1);
}
size = atoi(argv[1]);
int serv_sock_fd = socket(AF_INET,SOCK_STREAM,0);
int true = 1;
setsockopt(serv_sock_fd,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int));
if(serv_sock_fd == -1) {
perror("Failed to open server socket");
exit(1);
}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
// Bind socket to the chosen port
if ((bound_port = bind(serv_sock_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))) <0){
perror("Could not bind socket to local port");
exit(1);
}
// Listen on the port
if (listen(serv_sock_fd, 16))
{
perror("Could not listen");
exit(1);
}
signal(SIGINT, sigint_handler);
printf("Waiting for connection on %d ...\n", PORT);
int returned = 1;
while(returned) {
printf(".\n");
int new_socket_fd;
unsigned int client_addr_len = sizeof(client_addr);
if ((new_socket_fd = accept(serv_sock_fd, (struct sockaddr *)&client_addr,
&client_addr_len))<0) {
perror("Could not accept client connection");
exit(1);
}
printf("connection received, start sending ... ");
char * payload = sequence_payload(size);
returned = write(new_socket_fd, payload, size);
printf("finished sending\n");
printf("Returned value = %d\n", returned);
close(new_socket_fd);
free(payload);
}
close(serv_sock_fd);
return 0;
}
char * sequence_payload(int size) {
char * payload = malloc(size);
for (int i = 0; i < size; i++)
{
payload[i] = i%256;
}
return payload;
}
Basically what my code is doing is:
for the server: wait for a client to connect, send a dummy payload of the size wanted and close the connection to that client, repeat.
for the client: open a connection to the server, read what the server is sending until the server closes the connection, repeat until the decided timeout is reached.
To calculate the bandwidth, I can just do (number_of_connections_completed * size_transferred_by_connection) / duration_of_all_transfers. I use python to calculate the bandwidth, to be free of any overflow in C.
TLDR: The bandwidth I get with my C programs is 10 times less than what it should be on localhost. What could be the source of that problem?
malloc and free are the main issue here. Since they are system call they take a significant amount of time, and since I am measuring the performance of TCP and not those of memory allocation, malloc and free should be outside my profiled loop. Also, the same thing applies to printf in the server-side loop, while not as bad as malloc, the time it takes to print something on the screen is not something that should be taken into account when measuring the performance of TCP.
Related
I'm trying make the program run multiple threads to it connects to different ports. I successfully made it work on a single thread but not multiple.
Below I have posted the code of what I'm using on XUbuntu.
server.c
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
// File io storing in lof file
#include "server_portLog.h"
// Thread used to create sockets
#include "sockets_pthread.h"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
// Server port number
//int portNumber = atoi(argv[1]);
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
// Getting all ports from command line parameters and creating a socket for each
int numPorts = argc - 1;
struct port varPorts[numPorts];
pthread_t portsSockets[numPorts];
for (int i = 0; i < numPorts; i++) {
varPorts[i].portNumber = atoi(argv[i + 1]);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&portsSockets[i], &attr, createSocket, &varPorts[i]);
}
// Infinite loop too keep listening even after connection to client closes
while (1) {
// After that all the ports entered have a socket of their own the program runs them parallel together to see if any client tries to connect with one of the ports
for (int i = 0; i <= numPorts; i++) {
pthread_join(&portsSockets[i], NULL);
/* Start listening for the clients (thread blocks) */
if (listen(varPorts[i].sockfd, 5) != 0) {
printf("Error: listen() failed for port: %d \n", varPorts[i].portNumber);
//return 3;
}
// Accepting connection from client & creating socket with that client data
newsockfd = accept(varPorts[i].sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
printf("Error: accept() failed for port: %d \n", varPorts[i].portNumber);
//return 4;
}
/* To send receive data */
// Clearing buffer
memset(buffer, 0, BUFFER_SIZE);
// Show data received from client
num_bytes = recv(newsockfd, buffer, BUFFER_SIZE-1, 0);
if (num_bytes < 0) {
printf("Error: recv() failed for port: %d \n", varPorts[i].portNumber);
//return 5;
}
// Checking version of server if LOGFILE it creates a file to store the ports
#if defined LOGFILE
// Checking if user wrote a fileName for the logs or going to use the default log file
if (argc == 3) {
char *textFile = argv[argc-1];
serverLogFile_Custom(buffer, textFile);
}
else {
serverLogFile_Defualt(buffer);
}
#else
// Print the port numbers that connect to server
printf("Received: Client using port- %s to connect \n", buffer);
#endif
// Closing connection with client
close(newsockfd);
}
}
return 0;
}
Sockets_pthreads.h
#include <pthread.h>
struct port {
int portNumber;
int sockfd;
};
void* createSocket(void* portNumber) {
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
//char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
struct port *portStruct = (struct port*) portNumber;
// Creating a new socket with ip-Protocol_tcp
// Parameters: Internet-domain, socket-stream, TCP-protocol
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
printf("Error: Failed to open socket for port: %d \n", portStruct->portNumber);
//return 1;
}
// Setting all bits in padding-field to 0
memset(&serv_addr, 0, sizeof(serv_addr));
// Initializing socket in sockaddr_in (stucture)
serv_addr.sin_family = AF_INET; // Seting family-Internet
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portStruct->portNumber); // Setting portNum (passed in command line)
// Binding the address-structure to the socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("Error: bind() failed for port: %d \n", portStruct->portNumber);
//return 2;
}
// Geting sockfd
portStruct->sockfd = sockfd;
pthread_exit(0);
}
Problem is not clear what needs to be implemented. If various ports sockets have to accept, then it has to happen in thread function as well as recv call. In server function there are accept and recv calls which are blocking by default.
The main function should wait for connections. Upon receiving a request from the client, you create a thread that will handle this specific connection. So you will create the threads in the loop, meaning, you can theoretically have an infinite number of threads.
However, you can add a little logic to limit the number of threads that are existing at a particular time (thread pool).
So your main loop can look like this:
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t *) &clientlen);
if (childfd < 0){
fprintf(stderr,"ERROR on accept");
continue;
}
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL){
fprintf(stderr,"ERROR on inet_ntoa\n");
continue;
}
fprintf(stdout,"server established connection with client\n");
pthread_t new_thread;
newSock = malloc(1);
*newSock = childfd;
if( pthread_create( &new_thread , NULL , server_thread , (void*) newSock) < 0){
bzero(logMsg, MAXSTRING);
sprintf(logMsg, "Thread for connection %d could not be created",childfd);
fprintf(stderr, "%s\n", logMsg);
continue;
}
fprintf(stdout, "thread created for connection %d\n", childfd);
}
The server_thread function could look like:
void *server_thread(void* clientSock){
int childfd = *(int*)clientSock;
char buf[MAXLINE]; // message buffer
int n; // message byte size
char logMsg[MAXSTRING];
size_t siz_failresp;
// read: read input string from the client
bzero(buf, MAXLINE);
n = (int) read(childfd, buf, MAXLINE);
if (n < 0){
sprintf(logMsg, "ERROR reading from socket");
fprintf(stderr,"%s", logMsg);
close(childfd);
fprintf(stdout, "Client %d disconnected \n=================\n", childfd);
//Free the socket pointer
free(clientSock);
return NULL;
}
// else, do processing of data received...
// ...................
}
There may be unused variables here above... I just got this code from one of my projects, just removing parts that do not concern you :-)
Hope it helps
Here is a simple echo program using sockets and multi threads, it compiles and runs well in my Ubuntu if the client(via telnet) and server run on the same machine, but when I remotely connect to the server via telnet from another machine, it initially runs well(echos my message back every time), but some time later, there is no echo anymore even the telnet session is still alive, i am not sure where the problem is, can someone give some hits on this? I am new to multi thread programming and socket programming, learning on that.
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
void* worker(void* sockId)
{
int socketId = *(int*)sockId;
int data_len = 1;
char data[MAX_DATA];
while(data_len > 0)
{
data_len = recv(socketId, data, MAX_DATA, 0);
if (data_len > 0)
{
send(socketId, data, data_len, 0);
data[data_len] = '\0';
printf("Sent message: %s", data);
}
}
printf("Client disconnected\n");
close(socketId);
}
int main(int argc, char* argv[])
{
if (argc <= 1)
{
printf("missing argument: port\n");
exit(-1);
}
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new_connection;
int sockaddr_len = sizeof(struct sockaddr_in);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("server socket: ");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
server.sin_addr.s_addr = INADDR_ANY;
bzero(&server.sin_zero, 8);
if ((bind(sock, (struct sockaddr*)&server, sockaddr_len)) == ERROR)
{
perror("bind: ");
exit(-1);
}
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror("listen: ");
exit(-1);
}
while(1)
{
if ((new_connection = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror("accpet: ");
exit(-1);
}
printf("New Client connected from port: %d and IP: %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));
pthread_t thread;
pthread_create(&thread, NULL, worker, (void*)&new_connection);
pthread_detach(thread);
}
close(sock);
pthread_exit(NULL);
return 0;
}
Add some logging and you'll probably find that your code is blocked in send. You use naive, sequential I/O, so if the other end of the connection stops reading data, soon you do too.
I am new in Unix/Linux networking programming, so I have written server-client program in below.In this code there is one socket between client and server, client requests to server, then server responses from 1 to 100 numbers to client. So my question is how can we do this process with 3 socket( tcp connection) without using thread? ( e.g. First socket runs then second runs then third runs then first again. ) Do you have any suggestion?
Client.c
int main()
{
int sock;
struct sockaddr_in sa;
int ret;
char buf[1024];
int x;
sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(SERVER_PORT);
inet_pton (AF_INET, SERVER_IP, &sa.sin_addr);
ret = connect (sock,
(const struct sockaddr *) &sa,sizeof (sa));
if (ret != 0) {
printf ("connect failed\n");
exit (0);
}
x = 0;
while (x != -1) {
read (sock, buf , sizeof(int));
x = ntohl(*((int *)buf));
if (x != -1)
printf ("int rcvd = %d\n", x);
}
close (sock);
exit (0);
}
Server.c
int main()
{
int list_sock;
int conn_sock;
struct sockaddr_in sa, ca;
socklen_t ca_len;
char buf[1024];
int i;
char ipaddrstr[IPSTRLEN];
list_sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERVER_PORT);
bind (list_sock,(struct sockaddr *) &sa,sizeof(sa));
listen (list_sock, 5);
while (1){
bzero (&ca, sizeof(ca));
ca_len = sizeof(ca); // important to initialize
conn_sock = accept (list_sock,(struct sockaddr *) &ca,&ca_len);
printf ("connection from: ip=%s port=%d \n",inet_ntop(AF_INET, &(ca.sin_addr),
ipaddrstr, IPSTRLEN),ntohs(ca.sin_port));
for (i=0; i<100; ++i){
*((int *)buf) = htonl(i+20);
// we using converting to network byte order
write (conn_sock, buf, sizeof(int));
}
* ((int *)buf) = htonl(-1);
write (conn_sock, buf, sizeof(int));
close (conn_sock);
printf ("server closed connection to client\n");
}
}
I think it best to look at the excellent resource Beej's Guide to Netwokr Programming which goes into detail about this. He also has some good examples which you can use as a starting point and he covers all the major platforms including windows.
Basically you do:
socket()
bind()
listen()
accept()
accept() returns a socket connected to a unique client. Then you'd use select, poll or epoll to determine when data is available on those sockets. I suggest you can look at the man pages for these API's and Beej's guide. It's where I first learned network programming.
Looking at your code, your inner loop is wrong. When you accept a connection, you need to add it to a list or something. Currently, you overwrite it and loose it. You should use (e)poll or select to tell you which has data. You can write to any of them at any time. Again, look at the examples in Beej's guide, they are most helpful.
Maybe it's not exactly what you want,but I think you could try epoll,There is a simple example
typedef struct event_loop
{
int max_event;
int epfd;
}event_loop;
event_loop* create_event_loop()
{
event_loop *ep = malloc(sizeof(event_loop));
ep->max_event = 512;
ep->epfd = epoll_create(512);
return ep;
}
int add_event(event_loop *ep, int fd)
{
epoll_event ee;
ee.data.fd = fd;
ee.event = EPOLLIN | EPOLLPRI;
epoll_ctl(ep->epfd, EPOLL_CTL_ADD, fd, &ee);
}
void event_main(event_loop *ep, int listenfd)
{
epoll_event events[512];
int nfds, i, newfd;
while(1)
{
if(nfds = epoll_wait(ep->epfd, events, 512, -1) == -1)
exit(1);
for(i = 0; i < nfds; i++)
{
if(events[nfds].data.fd == listenfd)
{
newfd = accept(listenfd, NULL, NULL);
add_event(ep, newfd);
}
else
{
//do what you want
}
}
}
}
epoll is a high-efficiency solution,just man epoll get more information
I had earlier posted a question, regarding same, but over here i want guidance for my code. Using the tips from people I have tried to create for sending a packet. My max packet structure alongwith header and payload is of 16 bytes.Kindly if possible glance through the sending and receiving code and suggest where i am going wrong. Basically my client keeps sending data to server,it just doesn't end and server doesn't show results.
Client:
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
struct packet
{
long int srcID;
long int destID;
long int pver;
long int profiles;
char length;
long int data;
};
if (argc < 3) {
fprintf(stderr,"usage: %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]); //Convert ASCII to integer
sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket\n");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR DETECTED !!!, no such server found \n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr)); //clear the memory for server address
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
printf("Client 1 trying to connect with server host %s on port %d\n", argv[1], portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR in connection");
printf("SUCCESS !!! Connection established \n");
char buffer[128];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long int packet_size;
printf("Started Creating packet\n");
pkt->srcID = 0x01;
pkt->destID = 0x02;
pkt->pver = 0x01;
pkt->profiles = 0x01;
pkt->length = 128;
pkt->data = 1; 2; 3; 4; 5; 6; 7; 8;
if (send(sockfd,pkt,sizeof(packet_size),0) <0)
printf ("error\n");
else
printf ("packet send done");
return 0;
}
Server:
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
char wish;
long int SrcID;
long int DestID;
long int Pver;
long int Profiles;
long int Data;
char Length;
char bytes_to_receive;
char received_bytes;
struct packet
{
long int srcID;
long int destID;
long int pver;
long int profiles;
char length;
long int data;
};
if (argc < 2) {
fprintf(stderr,"usage: %s port_number1",argv[0]);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR DETECTED !!! There was a problem in binding");
listen(sockfd, 10);
clilen = sizeof(cli_addr);
printf("Server listening on port number %d...\n", serv_addr.sin_port);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR DETECTED !!! the connection request was not accepted");
char buffer[128];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long int packet_size;
bytes_to_receive = sizeof(pkt);
received_bytes = 0;
if (recv(newsockfd, pkt, sizeof(pkt), 0) < 0)
error("ERROR DETECTED !!! There was a problem in reading the data");
else
{
do {
received_bytes += (buffer + received_bytes, bytes_to_receive - received_bytes);
} while (received_bytes != bytes_to_receive);
SrcID = pkt->srcID;
DestID = pkt->destID;
Pver = pkt->pver ;
Profiles = pkt->profiles;
Length = pkt->length;
Data = pkt->data;
printf("Data Received from Client_1 are :\n");
printf("Source ID: %l\n", SrcID);
printf("Destination ID: %l\n", DestID);
printf("profile Version: %l\n", Pver);
printf("No of Profiles: %l\n", Profiles);
printf("Length: %l\n", Length);
printf("data : %l\n", Data);
}
if (close(newsockfd) == -1) {
error("Error closing connection with client 1");
}
printf("Connection with client 1 has been closed\n");
return 0;
}
The server is not showing any o/p. Client says it has send the packet. While compiling the server code i see four warnings saying unknown conversion type characters 0xa in format for all the printf statements in server code. I guess I am going wrong somewhere in the server code side, but I am not able to follow the "serialization". Please update me with your inputs, it would be of great help.
Here is couple of issues that I found:
Your client keep sending packages because it is in infinite while
loop.
You passed wrong len parameter of recv function. Right now
you pass sizeof(packet_size) which is equal to sizeof(long int) (4
bytes on 32 bit OS), but probably your intension was to use
sizeof(packet) (16 bytes).
You don't check how many bytes were
truly read by recv function. With TCP you don't have guaranties that
you read all 16 bytes of struct packet. So from time to time you
could read less bytes and your packet will be incomplete. Here is an
example in some pseudo code how you should receive whole packet:
bytes_to_receive = sizeof(packet)
received_bytes = 0;
do {
received_bytes += recv(buffer + received_bytes, bytes_to_receive - received_bytes)
} while (received_bytes != bytes_to_receive)
Your struct packet in client and server is different. In one you use char length; in second long int length;
I think also this kind of assignments in server make no sense pkt->srcID = SrcID; and should be something like this SrcID = pkt->srcID;
The problem with the client continually sending is because you simply have it in a loop. With indentation fixed, it becomes clear what has happened:
while (1)
{
if (send(sockfd,pkt,sizeof(packet_size),0) <0)
printf ("error\n");
else
printf ("packet send done");
}
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
EDIT: the code below has been fixed to receive and send properly AND to account for the actual bytes of messages sent annd recieved (latter thanks to EJP)
I'm programming with C in Unix.
I have server and client that are supposed to exchange msgs. While client seems to send messages fine, server doesn't receive the messages the client is sending. I've tried using recv() and read() (i know they are practically the same thing but with extra flags on recv()) but I have no luck and I'm not really sure what the problem really is.
I put sleep(3) in the client code after every time it sends a message but i see that once client and server are connected, server immediately closes without waiting for the incoming messages. What am i doing wrong?
This is the client-side code:
#define SERVER_TCP_PORT 11112
#define MAX_DATA_SIZE 500
int main(int argc, char * argv[])
{
int sockfd;
char * host;
char msg[MAX_DATA_SIZE];/* = "get my msg!\n";*/
int msg_len;
struct hostent * hp;
struct sockaddr_in client_address, server_address;
printf("y halo thar\n");
// looking up from the host database
if (argc == 2)
host = argv[1];
else
exit(1);
printf("sdf\n");
hp = gethostbyname(host);
if (!hp)
exit(1);
printf("host found\n");
// setting up address and port structure information
bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
bcopy(hp->h_addr, (char *) &server_address.sin_addr, hp->h_length);
server_address.sin_port = htons(SERVER_TCP_PORT);
printf("set\n");
// opening up socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
exit(1);
printf("opened\n");
// connecting
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0)
exit(1);
printf("connected\n");
int i;
for (i = 0; i < MAX_DATA_SIZE; ++i)
{
msg[i] = '.';
}
msg[MAX_DATA_SIZE-1] = '\0';
for(i = 0; i < 11; i++)
{
// send message to connected socket
msg_len = write(sockfd, msg, MAX_DATA_SIZE);
if(msg_len < 1)
printf("notsent\n");
else
printf("%i bytes sent\n", msg_len);
// recieve messages from connected socket
msg_len = read(sockfd, msg, MAX_DATA_SIZE);
if (msg_len < 1)
printf("not recieved\n");
else
{
printf("%i bytes received\n", msg_len);
printf(msg);
printf("\n");
}
}
// close connection
close(sockfd);
printf("closed\n");
}
and this is the server side
#define SERVER_TCP_PORT 11112
#define MAX_DATA_SIZE 500
int main()
{
printf("o halo thar\n");
int sockfd, new_sockfd;
int client_addr_len;
char msg [MAX_DATA_SIZE];
int msg_len;
char got_msg [11] = "got ur msg\0";
struct sockaddr_in server_address, client_address;
// setting up address and port structure information
bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_TCP_PORT);
// opening up socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
exit(1);
printf("socket is opened\n");
// binding
if (bind(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0)
exit(1);
printf("socket is bound\n");
// listening
listen(sockfd,5);
printf("listening\n");
// block and wait for an incoming connection
client_addr_len = sizeof(client_address);
new_sockfd = accept(sockfd, (struct sockaddr *) &client_address, &client_addr_len);
if (new_sockfd < 0)
exit(1);
printf("accepted\n");
int i;
for( i = 0; i < 11; i++)
{
// recieve messages from connected socket
printf("waiting\n");
msg_len = read(new_sockfd, msg, MAX_DATA_SIZE);
if (msg_len < 1)
{
printf("no msg recieved\n");
}
else
{
printf("bytes recieved: %i\n", msg_len);
}
// send message to connected socket
msg_len = write(new_sockfd, got_msg, sizeof(got_msg));
if (msg_len < 1)
printf("not sent\n");
else
printf("%i bytes sent\n", msg_len);
}
// close connection
close(sockfd);
printf("socket closed. BYE! \n");
}
In the server code, the problem is on this line:
msg_len = read(sockfd, msg, MAX_DATA_SIZE);
You are calling read on sockfd, but you need to call read or recv on new_sockfd (the socket returned by accept()). new_sockfd is the one that's connected to the client (sockfd is used to accept further connections - eg if another client connects).
You should read from the socket returned by accept.
Try to call read on the socket returned from accept.
Receiver Side:
while(1)
{
len=read(sd,buff,sizeof(buff));
if(len==0)
{
//End of File receving.
break;
}
else
{
st=fwrite(buff,sizeof(char),len,fp);
}
}
Send Side:
while(!feof(fp))
{
len=fread(buff,sizeof(char),MW,fp);
if(len==0)
{
//EOF
st=write(cd,&d,sizeof(int));
break;
}
else
{
st=write(cd,buff,len);
}
}
is the implementation based on stream or datagram?
there are some problem with your operation flow. the server might start to read before client send anything.
since client and server are separated, you can imagine them running concurrently.
right after your server side "accept" connection request, there might be possibly some handshake overhead occurs or network delays causing server app to execute ahead in time, attempt to extract data but meet with errors (no data received yet).
you can try this out by adding sleep in server code after accept connection, where client should have enough time to send the data.
another better solution is to make data retrieval cope with empty buffer or asynchronous read.