Related
I am writing a TCP client and server protocol for a school project. The client sends a "GET \r\n" message and the server has to transfer "+OK\r\n", size of the file and the file, in case it exists in the server directory. I'm blocked in the file transfer
I tried to solve it at small steps at a time. I set up the connection, sent the request from the client and received the "OK" message from the server.
Now I opened the file in the server and tried to send it 128 bytes at a time to the client. The reading of the file works and apparently also the sending of the buffers but the client is not receiving anything...
Here's my server.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* Buffer length */
#define TIMEOUT 15 /* TIMEOUT */
/* FUNCTION PROTOTYPES */
void service(int s);
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
int conn_request_skt; /* passive socket */
uint16_t lport_n, lport_h; /* port used by server (net/host ord.) */
int bklog = 2; /* listen backlog */
int s; /* connected socket */
fd_set cset; // waiting for connection
struct timeval tval; // timeout
size_t n;
socklen_t addrlen;
struct sockaddr_in saddr, caddr; /* server and client addresses */
prog_name = argv[0];
if (argc != 2) {
printf("Usage: %s <port number>\n", prog_name);
exit(1);
}
/* get server port number */
if (sscanf(argv[1], "%" SCNu16, &lport_h)!=1)
err_sys("Invalid port number");
lport_n = htons(lport_h);
/* create the socket */
printf("creating socket...\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done, socket number %u\n",s);
/* bind the socket to any local IP address */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address", &saddr);
Bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
/* listen */
printf ("Listening at socket %d with backlog = %d \n",s,bklog);
Listen(s, bklog);
printf("done.\n");
conn_request_skt = s;
/* main server loop */
for ( ; ; )
{
printf("waiting for connection...\n");
/* accept next connection */
FD_ZERO(&cset);
FD_SET(conn_request_skt, &cset);
tval.tv_sec = TIMEOUT;
tval.tv_usec = 0;
n = Select(FD_SETSIZE, &cset, NULL, NULL, &tval);
if ( n > 0 ){
addrlen = sizeof(struct sockaddr_in);
s = Accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s);
/* serve the client on socket s */
service(s);
} else {
printf("No connection request after %d seconds\n",TIMEOUT);
}
}
}
void service(int s) {
char buf[BUFLEN]; /* reception buffer */
char filename[BUFLEN];
int n;
long filesize;
uint32_t fsize;
FILE *fp;
for ( ; ; )
{
n = recv(s, buf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received request from socket %03d :\n", s);
sscanf(buf, "GET %s\r\n", filename);
strcpy(buf, "+OK\r\n");
printf("%s",buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while sending +OK\n");
// open file
fp = fopen(filename, "r");
if( fp == NULL){
//TODO close connection
}
// calculating dim of file
fseek(fp, 0L, SEEK_END);
filesize = ftell(fp);
rewind(fp); // go back at beginning of file
fsize = htonl(filesize); // size file in network byte order
// sending file size
if(writen(s, &fsize, 4) != 4)
printf("Write error while sending file size\n");
while(fread(buf, 1, BUFLEN - 1, fp) == BUFLEN - 1){
printf("%s", buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while buf\n");
}
printf("%s", buf);
printf("I am here\n");
}
}
}
While here is my client.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* BUFFER LENGTH */
#define TIMEOUT 15 /* TIMEOUT*/
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
char request[BUFLEN]; /* request buffer */
char rbuf[BUFLEN]; /* reception buffer */
uint32_t taddr_n; /* server IP addr. (net/host ord) */
uint16_t tport_n, tport_h; /* server port number (net/host ord) */
int s, len;
int result;
struct sockaddr_in saddr; /* server address structure */
struct in_addr sIPaddr; /* server IP addr. structure */
fd_set cset; // variables for timeout
struct timeval tval;
size_t n;
prog_name = argv[0];
if(argc < 4)
err_sys("Wrong number of parameters!\n");
// read address from first argument
taddr_n = inet_addr(argv[1]);
if (taddr_n == INADDR_NONE)
err_sys("Invalid address");
// read port number from second argument
if (sscanf(argv[2], "%" SCNu16, &tport_h)!=1)
err_sys("Invalid port number");
tport_n = htons(tport_h);
/* create the socket */
printf("Creating socket\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done. Socket fd number: %d\n",s);
/* prepare address structure */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = tport_n;
saddr.sin_addr = sIPaddr;
printf("trying to connect to the server...\n");
/* connect */
showAddr("Connecting to target address", &saddr);
Connect(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
// loop to request files
for (int i = 3 ; i < argc ; i++ ){ // i = 4 because the first file is the fourth argument
// check if file name is too big
if(strlen(argv[i]) >= BUFLEN - 6)
err_sys("The file name is too big for the buffer request!\n");
// create the string of bytes for the request
strcpy(request, "GET ");
strcat(request, argv[i]);
strcat(request, "\r\n");
len = strlen(request);
if(writen(s, request, len) != len){
printf("Write error\n");
break;
}
printf("waiting for response...\n");
// receive file from server
n = recv(s, rbuf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received reply from server\n");
uint32_t fsize;
printf("%s",rbuf);
if(strcmp(rbuf, "+OK\r\n") == 0){
n = recv(s, &fsize, 4, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
// received file dimension
fsize = ntohl(fsize);
}
while(fsize > 0){
printf("I am here1n\n");
// receive file
n = recv(s, rbuf, BUFLEN-1, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("I am here");
fsize -= n;
}
}
}
}
}
printf("===========================================================\n");
close(s);
exit(0);
}
The recv in the client where I am supposed to receive the file just blocks without receiving anything. I don't understand what I am missing...
The issue here is a common one: You're not being careful with message boundaries.
In your client, you do a recv and check whether the number of bytes is greater than 0. But then you don't do more length checking. You next do a strcmp on a particular string you're expecting to receive (+OK\r\n). But you might have received 3 bytes (+OK) or you might have received 10: (+OK\r\nXXXXX) or more [aside: also, recv doesn't guarantee your byte string is null-terminated]. There is nothing stopping the kernel on the far side from batching the preamble plus subsequent bytes into a single TCP packet. Likewise, there is nothing preventing the local side from aggregating multiple TCP packets into a single buffer.
You must provide message boundaries. If you're expecting your next message to be 5 bytes, then you should receive exactly 5 bytes (and retry if you get fewer -- being careful to check for EOF too in case the other side aborted early). Or, alternatively stick a buffering layer in front of your receive logic so that it will receive up to some large amount, return to you the number of bytes you want, and then save whatever is in excess for a subsequent "receive" call.
To restate this in a different way: Your server sends +OK\r\n, then it sends a four-byte length, then it starts sending the file. But that means your first recv on the client side could be receiving the preamble, plus the length, plus the first N bytes of the file all in one system call.
TCP does not respect, provide or enforce message boundaries.
I am sending a file from client to server along with its file name using TCP/IP. I have developed code, but I am not able to receive the file. I am giving the code for reference.
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/socket.h>
int receive_text(long long int socket)
{
long int buffersize = 0, recv_size = 0, size = 0, read_size, write_size;
char verify = '1',c;
int errno;
FILE *text;
char *pch;
char *str="/home/sosdt009/Documents";
char *fname[2];
char *filename[10];
char *filebody[1024];
int i=0;
//Find the size of the text
recv(socket, (char *)&size, sizeof(int), 0);
printf("Size value is:%ld\n",size);
//Send our verification signal
send(socket, &verify, sizeof(char), 0);
printf("Size value is:%ld\n",size);
//Make sure that the size is bigger than 0
if (size <= 0)
{
printf("Error has occurred. Size less than or equal to 0 \n");
return -1;
}
//Loop while we have not received the entire file yet
while (recv_size < size)
{
ioctl(socket, FIONREAD, &buffersize);
//We check to see if there is data to be read from the socket
if (buffersize > 0)
{
char *pBuf = malloc(buffersize);
printf("Buffer value is:%s\n",pBuf);
if (!pBuf)
{
fprintf(stderr, "Memory Error. Cannot allocate!\n");
exit(-1);
}
read_size = recv(socket, pBuf, buffersize, 0);
printf("read size is:%ld\n",read_size);
if (read_size < 0)
{
printf("%s", strerror(errno));
}
//printf ("Splitting string \"%s\" into tokens:\n");
pch = strtok (pBuf,"#");
printf(" value is:%s\n",pch);
while (pch != NULL)
{
filename[i]=pch;
strcpy(str,filename[i]);
printf("the string copy is: %s\n",str);
text = fopen(str, "w");
/*printf ("filename=%s\n",filename[i]);
pch = strtok (NULL, "#");*/
i++;
filebody[i]=pch;
printf ("filebody=%s\n",filebody[i]);
pch = strtok (NULL, "#");
while ((filebody[i] = strtok(NULL, "#")) != NULL)
printf("Next: %s\n",filebody[1024]);
//strcpy(filename[i],"filename");
//strcpy(filebody[i],pBuf);
//strcat(filename[i],filebody[i]);
pBuf=filename[i];
}
//Write the currently read data into our text file
write_size = fwrite(pBuf, 1, buffersize, text);
free(pBuf);
//Increment the total number of bytes read
recv_size += read_size;
}
}
fclose(text);
printf("File successfully Received! \n");
return 1;
}
int main(int argc , char *argv[])
{
long long int socket_desc , new_socket, c, read_size, buffer = 0;
struct sockaddr_in server , client;
char *readin;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 6777 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server ,sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("Bind completed");
//Listen
listen(socket_desc,3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
if((new_socket = accept(socket_desc,(struct sockaddr *)&client,(socklen_t *)&c)))
{
puts("Connection accepted");
}
fflush(stdout);
if (new_socket<0)
{
perror("Accept Failed");
return 1;
}
receive_text(new_socket);
close(socket_desc);
fflush(stdout);
return 0;
}
What you are trying to accomplish with this code is really unclear.
If I am correct, the code posted above is receiving data from the client and the loops process the data by storing storing some data in "filename" and "filebody" arrays respectively. You then try to open each filename and store its corresponding body data in a text file.
I think the problem is with the inner for loop where you are opening the file with each iteration. Since you are opening the file with the second arg as 'w' (writeable), you are overwriting hence deleting the existing content of the file. This may cause it to appear to have not received the file from the client.
Try opening the text file with the second argument as 'a' (append) instead of writeable and closing the file with each iteration. Also consider moving the statement:
write_size = fwrite(pBuf, 1, buffersize, text);
In the inner while loop.
I have a client which is working fine, but whenever I run a new client, sometimes I don't receive the sent message on the other client already running, while using telnet it works flawlessly, the message "broadcasts" to all connected clients, and I want whenever a message is received to one of the clients to show even if I didn't already send a message.
Should I use select on clients ? and what should be changed ?
client.c:
#include <stdio.h> //printf
#include <string.h> //strlen
#include <sys/socket.h> //socket
#include <arpa/inet.h> //inet_addr
#include <unistd.h>
int main(int argc , char *argv[]){
int sock;
struct sockaddr_in server;
char message[256] , server_reply[256];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 9034 );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0){
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
//keep communicating with server
for(;;){
printf("Enter message: ");
memset(message, 0, 256);
fgets(message, 256,stdin);
// scanf("%s" , message);
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
//Receive a reply from the server
if( recv(sock , server_reply , 256 , 0) < 0)
{
puts("recv failed");
break;
}
printf("Server Reply: %s\n", server_reply);
server_reply[0]='\0';
}
close(sock);
return 0;
}
server.c:
/*
** selectserver.c -- a cheezy multiperson chat server
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "9034" // port we're listening on
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void){
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR, below
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
// lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
// if we got here, it means we didn't get bound
if (p == NULL) {
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); // all done with this
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd);
}
} else {
// handle data from a client
memset(buf, 0, 256);
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
} else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)--and you thought it would never end!
return 0;
}
The reason a client can't receive a message until they send one is because.
fgets(message, 256,stdin);
Will keep "reading" (and will therefore block) until an EOF or a newline character has been read from the input stream
Also, note that
if( recv(sock , server_reply , 256 , 0) < 0)
blocks if there is nothing to read, which will prevent that user from sending more messages to the server until there is something new to read from the server. Assuming that you've played online games before, I hope that you can see that such a setup would be rather annoying!
So, we have to find someway of checking to see if we can read from STDIN and the server socket without incurring a block. Using select() will prevent us blocking on the sever socket, but it wouldn't work for STDIN whilst using fgets() to read input from the user. This is because, as mentioned above, fgets() blocks until an EOF or newline is detected.
The main solution I have in mind is to replace fgets with a method buffer_message() that will only read from STDIN when it won't block on read (we'll use select() to implement this). We'll then place what is read into a buffer. If there is a full message, this message will then be written to the server. Otherwise, we'll let the control keep going through the program until there is something to read or write.
This is code from a recent university assignment I did and so a small portion of the code isn't mine
Declarations:
//directives are above (e.g. #include ...)
//message buffer related delcartions/macros
int buffer_message(char * message);
int find_network_newline(char * message, int inbuf);
#define COMPLETE 0
#define BUF_SIZE 256
static int inbuf; // how many bytes are currently in the buffer?
static int room; // how much room left in buffer?
static char *after; // pointer to position after the received characters
//main starts below
Main:
//insert the code below into main, after you've connected to the server
puts("Connected\n");
//set up variables for select()
fd_set all_set, r_set;
int maxfd = sock + 1;
FD_ZERO(&all_set);
FD_SET(STDIN_FILENO, &all_set); FD_SET(sock, &all_set);
r_set = all_set;
struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0;
//set the initial position of after
after = message;
puts("Enter message: ");
//keep communicating with server
for(;;){
r_set = all_set;
//check to see if we can read from STDIN or sock
select(maxfd, &r_set, NULL, NULL, &tv);
if(FD_ISSET(STDIN_FILENO, &r_set)){
if(buffer_message(message) == COMPLETE){
//Send some data
if(send(sock, message, strlen(message) + 1, 0) < 0)//NOTE: we have to do strlen(message) + 1 because we MUST include '\0'
{
puts("Send failed");
return 1;
}
puts("Enter message:");
}
}
if(FD_ISSET(sock, &r_set)){
//Receive a reply from the server
if( recv(sock , server_reply , 256 , 0) < 0)
{
puts("recv failed");
break;
}
printf("\nServer Reply: %s\n", server_reply);
server_reply[0]='\0';
}
}
close(sock);
return 0;
//end of main
Buffer functions:
int buffer_message(char * message){
int bytes_read = read(STDIN_FILENO, after, 256 - inbuf);
short flag = -1; // indicates if returned_data has been set
inbuf += bytes_read;
int where; // location of network newline
// Step 1: call findeol, store result in where
where = find_network_newline(message, inbuf);
if (where >= 0) { // OK. we have a full line
// Step 2: place a null terminator at the end of the string
char * null_c = {'\0'};
memcpy(message + where, &null_c, 1);
// Step 3: update inbuf and remove the full line from the clients's buffer
memmove(message, message + where + 1, inbuf - (where + 1));
inbuf -= (where+1);
flag = 0;
}
// Step 4: update room and after, in preparation for the next read
room = sizeof(message) - inbuf;
after = message + inbuf;
return flag;
}
int find_network_newline(char * message, int bytes_inbuf){
int i;
for(i = 0; i<inbuf; i++){
if( *(message + i) == '\n')
return i;
}
return -1;
}
P.S.
if( send(sock , message , strlen(message) , 0) < 0)
The above can also block if there's no space to write to the server, but there's no need to worry about that here. Also, I'd like to point out a few things you should implement for your client and your server:
Whenever you send data over a network, the standard newline is \r\n, or carriage return / newline, or simply the network newline. All messages sent between the client and the server should have this appended at the end.
You should be buffering all data sent between the server and the client. Why? Because you're not guaranteed to receive all packets in a message in a single read of a socket. I don't have time to find a source, but when using TCP/IP, packets for a message/file don't have to arrive together, meaning that if you do read, you may not be reading all of the data you intend to read. I'm not well versed in this, so please investigate this more. Open to having this edited / corrected
i have implemented a program which takes input from client, performs operation on server and writes the data to the client. ls command is what i have chosen for example.
Now my doubt is,
1) what if the input is very huge in bytes??
2) what is the maximum data that can be sent through a socket port??
client.c
int main()
{
FILE *fp;
int servfd, clifd;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
int cliaddr_len;
char str[4096], clientip[16];
int n;
servfd = socket(AF_INET, SOCK_STREAM, 0);
if(servfd < 0)
{
perror("socket");
exit(5);
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVPORT);
servaddr.sin_addr.s_addr = inet_addr(SERVIP);
if(bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(0);
}
listen(servfd, 5);
printf("Server is waiting for client connection.....\n");
while(1)
{
cliaddr_len=sizeof(cliaddr);
clifd = accept(servfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
strcpy(clientip, inet_ntoa(cliaddr.sin_addr));
printf("Client connected: %s\n", clientip);
if(fork() == 0)
{
close(servfd);
while(1)
{
n = read(clifd, str, sizeof(str));
str[n] = 0;
if(strcmp(str, "end") == 0)
{
printf("\nclient(%s) is ending session and server is waiting for new connections\n\n", clientip);
break;
}
else if (strcmp(str, "ls") == 0) {
system("ls >> temp.txt");
fp = fopen("temp.txt", "r");
fread(str, 1, 500, fp);
remove("temp.txt");
}
else
printf("Received from client(%s): %s\n", clientip, str);
write(clifd, str, strlen(str));
}
close(clifd);
exit(0);
}
else
{
close(clifd);
}
}
}
server.c
int main()
{
int sockfd;
struct sockaddr_in servaddr;
char str[500];
int n;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVPORT);
servaddr.sin_addr.s_addr = inet_addr(SERVIP);
if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
printf("Could not connect to server: %s\n", strerror(errno));
exit(1);
}
while(1)
{
printf("Enter message: ");
scanf(" %[^\n]", str);
write(sockfd, str, strlen(str));
if(strcmp(str, "end") == 0)
break;
n = read(sockfd, str, sizeof(str));
str[n] = 0;
printf("Read from server: %s\n", str);
}
close(sockfd);
}
As for your question no 1. the huge data is broken in many packets & then sent packet by packet its done by OS internally. & the one packet size depends on your system OS(you can change it.It is called MTU maximum transfer unit).
& for your question no 2. the data send by a socket port may be infinite coz as long as u wish to send data it will send. there is no limit.!!!
Q: What if the input is very huge in bytes?? What is the maximum data that can be sent through a socket port??
A: There is no limit on the size of a TCP/IP stream. In theory, you could send and receive an infinite number of bytes.
... HOWEVER ...
1) The receiver must never assume is will ever get all the bytes at once, in a single read. You must always read socket data in a loop, reading as much at a time as you wish, and appending it to the data you've already read.
2) You can send a "large" amount of data at once, but the OS will buffer it behind your back.
3) Even then, there's an OS limit. For example, here the maximum send buffer size is 1 048 576 bytes.:
http://publib.boulder.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_send.html
If you need to send more, you must send() in a loop.
PS:
As Anish recommended, definitely check out Beej's Guide to Network programming:
http://beej.us/guide/bgnet/output/html/multipage/
I am working on a client server program , that uses select() calls to listen to multiple sockets. But my select call gets blocked, although I have a message in one of those sockets , select() call doesn't recognize it and it's still waits there indefinetly.
There are 2 entities in the program , a master and a client.
The master knows the number of clients it will handle and waits for the clients to connect to it. Once it receives a client acknowledgement, it stores its information. Once all the clients are connected, it then sends its neighboring client's information to every client so it can form a network. It is here, I use the select() to monitor many sockets,
master has a socket to every child tat is connected to it
client has 3 main sockets
s1-to speak with master
s2-child listens for connection on this socket
neighbour-the socket on which its neighbour wait for a connection.(i.e S2 in a neighbour)
p- the socket that is results of connection from its neighbour ( accept of s2 - returns ths)
I use select to listen to server, its own socket for incoming connections and once.
Initially my server sends a string "hello" to one of the client, which receives this message and passes it on to the neighbour, in this way when the string reaches back to the first child that has received this message from server , it passes it on to its neighbour. But all though all child are in select() waiting for an input. What could cause this ??
void main(int argc, char **argv) {
int s1, s2, n, server_port, sc1, sc2, rv, rc, left_peer_port;
int peer_port;
fd_set writefds, readfds;
struct timeval tv;
struct hostent *server_info, *child_info, *left_peer_info;
int start_flag = 0;
struct sockaddr_in server, peer, incoming;
char host_child[64];
char *left_host = malloc(1);
char *right_host = malloc(1);
char buf1[256];
char buf2[256];
server_port = atoi(argv[2]);
//speak to peer using this
s2 = socket(AF_INET, SOCK_STREAM, 0);
if (s2 < 0) {
perror("socket:");
exit(s2);
}
peer_port = server_port + 1;
gethostname(host_child, sizeof host_child);
child_info = gethostbyname(host_child);
if (child_info == NULL) {
fprintf(stderr, "%s: host not found (%s)\n", argv[0], host_child);
exit(1);
}
peer.sin_family = AF_INET;
memcpy(&peer.sin_addr, child_info->h_addr_list[0], child_info->h_length);
int changeport = 0;
do {
peer.sin_port = htons(peer_port);
rc = bind(s2, (struct sockaddr *) &peer, sizeof(peer));
if (rc < 0) {
//perror("bind:");
peer_port++;
changeport = 1;
//exit(rc);
} else {
changeport = 0;
}
} while (changeport == 1);
if (listen(s2, 100) == -1) {
perror("listen");
exit(3);
}
//Now talk to server
server_info = gethostbyname(argv[1]);
if (server_info == NULL) {
fprintf(stderr, "%s: host not found\n", argv[0]);
exit(1);
}
// pretend we've connected both to a server at this point
//speak to server using this
s1 = socket(AF_INET, SOCK_STREAM, 0);
if (s1 < 0) {
perror("socket:");
exit(s1);
}
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
memcpy(&server.sin_addr, server_info->h_addr_list[0], server_info->h_length);
//To talk to the server
sc1 = connect(s1, (struct sockaddr *) &server, sizeof(server));
if (sc1 < 0) {
perror("connect:");
exit(sc1);
}
int send_len;
char *str = malloc(1);
sprintf(str, "%d", peer_port);
printf("\nport-here=%s\n", str);
send_len = send(s1, str, strlen(str), 0);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
int recv_len;
char buf[100];
int ref = 0;
int recv_stage = 0;
int start_id;
recv_len = recv(s1, buf, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf[recv_len] = '\0';
char *temp_port;
if (!strcmp("close", buf))
printf("%s", buf);
//break;
else {
char *temp_buffer = malloc(1);
char *id = malloc(100);
char *pp = malloc(1);
strcpy(temp_buffer, buf);
char *search = ":";
temp_port = strtok(temp_buffer, search);
strcpy(buf, temp_port);
printf("temp_name%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(pp, temp_port);
printf("temp_port%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(id, temp_port);
printf("id%s", temp_port);
strcpy(temp_port, pp);
printf("\nbuf=%s\n", buf);
printf("\nport=%s\n", temp_port);
printf("\nid=%s\n", id);
start_id = atoi(id);
}
//To send packet to its neighbour
left_peer_info = gethostbyname(buf);
printf("\nleft host=%s\n", buf);
if (left_peer_info == NULL) {
fprintf(stderr, "%s: host not found\n", left_host);
exit(1);
}
left_peer_port = atoi(temp_port);
int neighbour_socket;
struct hostent *neighbour_info;
struct sockaddr_in neighbour;
neighbour_socket = socket(AF_INET, SOCK_STREAM, 0);
if (neighbour_socket < 0) {
perror("socket:");
exit(neighbour_socket);
}
neighbour_info = left_peer_info;
neighbour.sin_family = AF_INET;
neighbour.sin_port = htons(left_peer_port);
memcpy(&neighbour.sin_addr, neighbour_info->h_addr_list[0], neighbour_info->h_length);
printf("\nconnected to port %d\n", left_peer_port);
//To talk to the neighbour
printf("\ncomes here\n");
//Listen on this socket connection for potato
int send_peer_len;
int nfds;
nfds = MAX(MAX(neighbour_socket, s2), s1);
// clear the set ahead of time
FD_ZERO(&writefds);
// add our descriptors to the set
FD_SET(neighbour_socket, &writefds);
FD_SET(s1, &writefds);
FD_SET(s2, &writefds);
//FD_SET(s2, &writefds);
FD_ZERO(&readfds);
FD_SET(neighbour_socket, &readfds);
FD_SET(s1, &readfds);
FD_SET(s2, &readfds);
//select()
// since we got s2 second, it's the "greater", so we use that for
// the n param in select()
//n = s1 + 1;
// wait until either socket has data ready to be recv()d (timeout 10.5 secs)
tv.tv_sec = 10;
tv.tv_usec = 500000;
int fds[3];
fds[0] = s1;
fds[1] = s2;
fds[2] = neighbour_socket;
int p = 0;
int p_flag = 0;
while (1) {
printf("\n nfds = %d , p = %d \n", nfds, p);
char buf_msg[64];
//This is where the error occurs //
rv = select(nfds, &readfds, NULL, NULL, 0);
//This is where the error occurs //
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred! No data after 10.5 seconds.\n");
} else {
// one or both of the descriptors have data
//reading message from server
int select_fd;
for (select_fd = 0; select_fd <= nfds; select_fd++) {
if (FD_ISSET(select_fd, &readfds) != 0) {
if (select_fd == s1) {
recv_len = 0;
recv_len = recv(s1, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from server = %s\n", buf_msg);
//send to neighbour
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
exit(sc3);
}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s1 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
start_flag = 1;
//FD_CLR(s1, &readfds);
printf("\ncrossed server\n");
} else if (select_fd == s2) {
int list_len = sizeof incoming;
printf("\ninside client\n");
printf("\nWaiting for accept in S2\n");
if (p_flag == 0) {
p_flag = 1;
p = accept(s2, (struct sockaddr *) &incoming, &list_len);
printf("\nConnection accepted in S2\n");
if (p < 0) {
perror("bind:");
exit(rc);
}
}
nfds = MAX(nfds, p);
recv_len = 0;
buf_msg[recv_len] = '\0';
recv_len = recv(p, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
//if(start_id!=1){
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
//exit(sc3);
}
//}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s2 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
} else if (select_fd == neighbour_socket) {
printf("\ncomes in\n");
} else if (select_fd == p && p != 0) {
int list_len = sizeof incoming;
printf("\ninside p\n");
recv_len = 0;
buf_msg[recv_len] = '\0';
printf("\nwaiting at recv in P\n");
recv_len = recv(p, buf_msg, 34, 0);
printf("\ncrossed at recv in P\n");
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - neighbour - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
}
}
}
FD_ZERO(&readfds);
//FD_SET(neighbour_socket,&readfds);
FD_SET(s1, &readfds);
FD_SET(neighbour_socket, &readfds);
if (p_flag == 1) {
printf("\nsetting P\n");
FD_SET(p, &readfds);
FD_SET(s2, &readfds);
p_flag = 0;
} else {
printf("\nNot setting P\n");
FD_SET(s2, &readfds);
}
}
}
close(s1);
close(s2);
}
Thanks in advance.
The first parameter to select must be the maximum file descriptor plus one. As far as I can tell in that huge lump of code you posted, you forgot that "plus one".
I believe Mat has found the underlying problem. But I think there is a much larger problem here:
int send_len;
char *str=malloc(1);
sprintf(str,"%d",peer_port);
printf("\nport-here=%s\n",str);
You have corrupted your heap with your sprintf(3) call. Maybe it isn't important data you've overwritten, and maybe malloc(3) won't ever actually allocate one byte, but that is a bad assumption to make. You need to allocate at least six bytes for a port number: five for the digits in 65535 and one for the trailing ASCII NUL \0 byte.
buf[recv_len] = '\0';
char *temp_port;
//printf("\n-%s\n",buf);
if ( !strcmp("close", buf) )
printf("%s",buf);
//break;
else{
char *temp_buffer=malloc(1);
char *id=malloc(100);
char *pp=malloc(1);
strcpy(temp_buffer,buf);
In the preceding selection, you have stored a \0 into the end of buf, so you're presumably working with a string of some sort. But in a few lines, you allocate a single byte and then proceed to copy the contents of buf into that single byte. The ASCII NUL will use that byte entirely, leaving no space for the string you received. But strcpy(3) doesn't work that way -- it will copy the contents of buf, until that '\0' character, into the memory starting with your single byte. You've again destroyed your heap. But this time it can overwrite significantly more than five bytes -- and all under the control of the remote peer.
Heap overflows are extremely dangerous. I found over 350 references to exploitable bugs in programs that derive directly from heap overflows in an old archive I have from the Common Vulnerabilities and Exposures project.
Do not deploy this program on publicly-accessible machines until you have fixed these problems. It represents a significant security flaw. Find every instance of malloc(1) and replace it with the correct amount of memory that must be allocated. Once you've done this, please run your program with MALLOC_CHECK_=1 or under control of valgrind(1) to help you find further memory allocation problems.
Have you considered using poll() instead of select()? It's easier to debug and scales elegantly to however many you need.