Related
I have a server-client program written in C. My problem is that I have a while loop in which I receive and send data. it happens a lot when i need my server to do other things but it just stops at recv() function and waits for data from client. How can I overcome it? I've tried this:
int waitForAnswer =1;
if((childpid = fork()) == 0){
close(socketfd);
close(fd[0]);
while(1){
if(waitForAnswer) {
receive(newSocket, buff) == 0;
parseRecvMess(buff);
}
waitForAnswer =0;
but it doesn't work. For some reason the program finishes with an exit code 1, at accepting socket with a "No Socket" error.
Here is my program ;
nt main(){
int size = 256;
char buff[size];
char sbuff[size];
int n;
int reader;
int socketfd, ret;
struct sockaddr_in serverAddr;
int newSocket = -2;
struct sockaddr_in newAddr;
socklen_t addr_size;
pid_t childpid;
pocet_hracu = 0;
srand(time(NULL));
initializeLobby();
memset(buff, 0, size);
memset(sbuff, 0, size);
socketfd = socket(AF_INET,SOCK_STREAM,0);
if(socketfd < 0){
printf("\n error in socket creation");
return -1;
}
printf("\n Server socket is created\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(socketfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("Error in binding\n");
return -1;
}
printf("[*]Bind to port %d\n", PORT);
if(listen(socketfd, 10) == 0){
printf("Listening...\n");
}else{
printf("Error in binding\n");
}
// pipe pro komunikaci
int readpipe;
int writepipe;
int fd[2];
pipe(fd);
for (;;) {
newSocket = accept(socketfd, (struct sockaddr *) &newAddr, &addr_size);
if (newSocket < 0) {
printf("No socket\n");
exit(1);
}
// struct timeval tv;
// tv.tv_sec = 1;
// tv.tv_usec = 0;
// setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
// read the message from client and copy it in buffer
receive(newSocket, buff);
parseRecvMess(buff);
printf("\n%s sent: %s", user, command);
if (strncmp(" new", command, 4) == 0) {
player newPlayer;
newPlayer.name = (char *) malloc(sizeof(char) * 10); // *login must contain up to 10 characters
strcpy(newPlayer.name, user);
newPlayer.gameScore = 0;
newPlayer.roundScore = 0;
newPlayer.socket = newSocket;
// TODO vztvorit pipe pro kounikaci
// newPlayer.readpipe
// newPlayer.writepipe
addToPlayersArray(&newPlayer); //TODO player index is not increasing
addToLobby(&newPlayer);
printf("Server : %s uspesne prihlasen.\n", newPlayer.name);
}
bzero(buff, size);
printf("To client : OK\n");
strcpy(sbuff, "OK\n" );
sendMess(newSocket, sbuff, sizeof(sbuff));
int waitForAnswer =1;
if((childpid = fork()) == 0){
close(socketfd);
close(fd[0]);
while(1){
printf("MAIN->while(1)\n");
// poslouchame zpravy
//if(waitForAnswer) {
receive(newSocket, buff) == 0;
parseRecvMess(buff);
//}
waitForAnswer =0;
if(strcmp(buff,":exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
break;
} else{
// send buff to parent
int i = findPlayerIndex();
memset(sbuff, '\0', size) ;
str str;
strcat(sbuff, "//:");
sprintf(str, "%d", i);
strcat(sbuff, str);
strcat(sbuff, ":");
strcat(sbuff, command);
strcat(sbuff, "\n");
write(fd[1], sbuff , strlen(sbuff)+1);
bzero(buff, sizeof(buff));
if (strncmp("roll", command, 4) == 0) {
//TODO
hod();
}
if (strncmp("none", command, 4) == 0) {
//TODO
}
strcpy(sbuff, "OK\n" );
write(newSocket, sbuff, strlen(sbuff));
bzero(buff, sizeof(buff));
bzero(sbuff, sizeof(sbuff));
}
}
}
close(fd[1]);
int nbytes = read(fd[0], buff, sizeof(buff));
printf("PARENT: buffer : %s\n",buff);
parseRecvMess(buff);
char *index1= (char *)malloc(sizeof(char)*10);
strcpy(index1, user);
int index = atoi(index1);
char *command1= (char *)malloc(sizeof(char)*10);
strcpy(command1, command);
//printf("PARENT - index:%d, command:%s\n", index, command );
printf("PARENT - index:%d, jmeno:%s, command:%s\n", index, players_array[index].name, command1 );
bzero(buff, sizeof(buff));
if (strncmp("room", command1, 4) == 0) {
// vlozit do mistnosti
printf("command = room\n");
command = strtok(command1," ");
command = strtok(NULL," "); // volba
printf("command(volba): + %s \n", command);
//int i = findPlayerIndex(); // find player in array based on user name
printf("player index: = %d \n", index);
//printPlayer(&players_array[i]);
volbaHry(&players_array[index], command, lobby);
//players_array[i].mist->pocet_hracu++;
printf("PARENT: array pocet hracu %d\n",players_array[index].mist->pocet_hracu);
printf("PARENT: lobby pocet hracu %d\n",lobby[0].pocet_hracu);
str str;
memset(sbuff, '\0', size);
//pokud v mistnosti jsou 2 hraci => zacina hra
if( players_array[index].mist->pocet_hracu == 2){
printf("Hra zacina ...\n");
hra(players_array[index].mist);
}
printMistnost(players_array[index].mist);
}
//players_array[index].mist = lobby[volba - 1];
// }
}
close(newSocket);
return 0;
}
and this is my receive() function:
int receive(int socket, char *buff){
int size = 256;
int reader = recv(socket, buff, size * sizeof(char), 0);
if (reader == -1) {
printf("BREAK reader == -1\n");
perror("recv()");
return(-1);
} else if (reader == 0) {
printf("BREAK reader == 0\n");
return(-2);
} else if(checkMessage(buff) == 0){
printf("ERROR: recieved message is not valid\n");
return(-3);
}
return 0;
}
if I'm not using waitForAnswer variable the program connects without any errors with the client, but at some points stops at the beginning of while waiting for another message.
You can also use ioctl() to check for data if the socket is set to non blocking
#include <sys/ioctl.h>
int status;
do{
ioctl(socketfd, FIONREAD, &status);
if( status > 0 ){
//packet waiting to be read
recv(socketfd, buff, size * sizeof(char), 0);
}
else{
// no data .. so do something else
}
} while (!must_stop);
Call recv with the nonblocking flag:
recv(socket, buff, size, MSG_DONTWAIT);
And the function will immediately return if there was no data to read.
I want to build a chat program, but the problem is that once client sends a message to server, all other client will receive this message from server, but client don't know when the message will come. In the client's main loop it will block on fgets() and wait for user to input a command or message. I need the client program to receive the message and print it while waiting for input from user. How can I do that ?
here's the code:
I haven't write recv for message since I don't know where to put it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
#define LOGIN 1
#define LO_ACK 2
#define LO_NACK 3
#define EXIT 4
#define JOIN 5
#define JN_ACK 6
#define JN_NACK 7
#define LEAVE_SESS 8
#define NEW_SESS 9
#define NS_ACK 10
#define MESSAGE 11
#define QUERY 12
#define QU_ACK 13
struct packet {
unsigned int type;
unsigned int size;
char source[20];
char data[500];
};
int encode(struct packet temp, char *data) {
sprintf(data, "%d:%d:%s:", temp.type, temp.size,
temp.source);
int length = strlen(data);
int i;
for (i = 0; i < temp.size; i++) {
data[length + i] = temp.data[i];
}
data[length + i] = '\0';
return length;
}
struct packet decode(char *data) {
int i, j;
struct packet message;
char temp[100];
char source[20];
sscanf(data, "%d:%d", &message.type, &message.size);
sprintf(temp, "%d:%d", message.type, message.size);
int length = strlen(temp);
for (i = length + 1; data[i] != ':'; i++) {
message.source[i - length - 1] = data[i];
}
for (j = 0; j < message.size; j++) {
message.data[j] = data[j + i + 1];
}
return message;
}
int main(void) {
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
int login = 0;
char me[20];
while (1) {
char buf[500];
char input[100];
char *command;
char arg1[20], arg2[20], arg3[20], arg4[20], arg5[20];
int i, j, k, l, m;
fgets(input, 100, stdin);
if (strlen(input) < 3)
continue;
if (input[0] == '/') {//command
command = &input[1];
//get first argument
for (i = 0; command[i] != '\0' && command[i] != ' '; i++) {
arg1[i] = command[i];
}
//arg1[i] = '\0';
if (strcmp(arg1, "login") == 0) {//login
//get id,password,ip,port
if (login == 1) {
printf("error: already login\n");
continue;
}
for (j = i + 1; command[j] != '\0' && command[j] != ' '; j++) {//id
arg2[j - i - 1] = command[j];
}
//arg1[j-i+1] = '\0';
for (k = j + 1; command[k] != '\0' && command[k] != ' '; k++) {//password
arg3[k - j - 1] = command[k];
}
for (l = k + 1; command[l] != '\0' && command[l] != ' '; l++) {//ip
arg4[l - k - 1] = command[l];
}
for (m = l + 1; command[m] != '\0'; m++) {//port
arg5[m - l - 1] = command[m];
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(arg4, arg5, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
freeaddrinfo(servinfo);
struct packet tosend;
tosend.type = LOGIN;
sprintf(tosend.data, "%s %s", arg2, arg3);
strcpy(tosend.source, arg2);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
usleep(100);
recv(sockfd, buf, strlen(buf), 0);
struct packet reply;
reply = decode(buf);
if (reply.type == LO_ACK) {
printf("login successful\n");
strcpy(me, arg2);
login = 1;
continue;
} else if (reply.type == LO_NACK) {
printf("login failed: %s\n", reply.data);
continue;
}
} else if (strcmp(arg1, "createsession") == 0) {
if (login == 0) {
printf("error: not login\n");
continue;
}
for (j = i + 1; command[j] != '\0'; j++) {//session name
arg2[j - i - 1] = command[j];
}
struct packet tosend;
tosend.type = NEW_SESS;
strcpy(tosend.data, arg2);
strcpy(tosend.source, me);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
usleep(100);
recv(sockfd, buf, strlen(buf), 0);
struct packet reply;
reply = decode(buf);
if (reply.type == NS_ACK) {
printf("create session successful\n");
continue;
} else if (reply.type == JN_ACK) {
printf("session already exist, join session successful\n");
continue;
}
} else if (strcmp(arg1, "joinsession") == 0) {
if (login == 0) {
printf("error: not login\n");
continue;
}
for (j = i + 1; command[j] != '\0'; j++) {//session name
arg2[j - i - 1] = command[j];
}
struct packet tosend;
tosend.type = JOIN;
strcpy(tosend.data, arg2);
strcpy(tosend.source, me);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
usleep(100);
recv(sockfd, buf, strlen(buf), 0);
struct packet reply;
reply = decode(buf);
if (reply.type == JN_ACK) {
printf("join session successful\n");
continue;
}
} else if (strcmp(arg1, "leavesession") == 0) {
if (login == 0) {
printf("error: not login\n");
continue;
}
struct packet tosend;
tosend.type = LEAVE_SESS;
strcpy(tosend.data, "none");
strcpy(tosend.source, me);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
printf("leave session successful\n");
continue;
} else if (strcmp(arg1, "list") == 0) {
if (login == 0) {
printf("error: not login\n");
continue;
}
struct packet tosend;
tosend.type = QUERY;
strcpy(tosend.data, "none");
strcpy(tosend.source, me);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
usleep(100);
recv(sockfd, buf, strlen(buf), 0);
struct packet reply;
reply = decode(buf);
printf("%s", reply.data);
continue;
} else {
printf("invalid command\n");
continue;
}
} else {//message
if (login == 0) {
printf("error: not login\n");
continue;
}
struct packet tosend;
tosend.type = MESSAGE;
strcpy(tosend.data, input);
strcpy(tosend.source, me);
tosend.size = strlen(tosend.data);
char message[500];
encode(tosend, message);
send(sockfd, message, strlen(message), 0);
continue;
}
}
}
'client don't know when to recv' that's easy: all the time.
There are multiple options:
1) select() on fd's, including stdin (Google for details).
2) poll/epoll() - as above, but improved performance.
3) Have a thread that waits on input and fires messages onto a producer-consumer queue to another 'state-machine' thread that handles those messages, and messages from other threads that handle client recv() data from the server, and performs the required actions.
4) Any other mechanism that might be available from your particular OS.
Check this code here:
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
int main()
{
fd_set fds;
while(1){
FD_ZERO(&fds); // you NEED to zero this every loop
FD_SET(STDIN_FILENO, &fds);
// add your socket here
// first argument here will be your socket + 1
select(STDIN_FILENO + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(STDIN_FILENO, &fds)){
char buffer[128];
fgets(buffer, sizeof(buffer), stdin);
printf("User input - stdin: %s", buffer);
}
// here check if your socket is set and act accordingly
}
return 0;
}
It will read from stdin using select (http://man7.org/linux/man-pages/man2/select.2.html), you can use it as a base to study how select works and expand it for your needs.
You will need to add your socket in the fds so it will wait on the select until either there is an user input to process or there is data on your socket (use FD_ISSET to check).
Good luck.
PS: I used the code from this question Using stdin with select() in C as a base to produce the one I posted.
I am running a client which sends from the command line a timezone, and a test server (which we know works), returns the date and time for that timezone. However after returning the timezones, correctly, it segfaults.
Below is my client code:
int main(int argc, const char * argv[]){
char buf[kBufSize+1];
char line[128];
ssize_t n;
int i;
int more;
int x = 0;
int sockFD;
int port;
struct sockaddr_in sad;
struct hostent *ptrh;
sockFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&sad, 0, sizeof(sad)); /* Sets every byte of the address to be zero */
sad.sin_family = AF_INET;
/* Look up name */
ptrh = gethostbyname(argv[1]);
memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
/* Set port */
//sscanf(argv[2], "%d", &port);
port = atoi(argv[2]);
//printf("%d",port);
sad.sin_port = htons(port);
int clifd = connect(sockFD, (struct sockaddr *)&sad, sizeof(sad));
if(clifd < 0) {
printf("[ERROR]: Error Connecting...\n");
return 0;
}
printf("Number of args: %d\n", argc);
x = 3;
//printf("Value of x: %d\n", x);
//printf("[DEBUG]: Value of X: %d\n", x);
//printf("[DEBUG]: Line: %s\n", line);
do
{
/* Read input line */
do
{
more = 1;
n = read(sockFD, buf, kBufSize);
buf[n] = '\0'; // BUF IS READ FROM THE SERVER
if(n <= 0)
break;
for(i = 0; i < n; i++)
{
if(buf[i] == 10)
{
more = 0;
break;
}
}
printf("%s", buf);
if (buf == "BYE\r\n"){
printf("Closing\n");
exit(1);
}
} while(more);
if(n <= 0)
{
break;
}
strcpy(line, argv[x]);
strcat(line, "\r\n\0"); // LINE IS SENT TO THE SERVER
//printf("[DEBUG] Being sent: %s", line);
write(sockFD, line, strlen(line));
//printf("%d", n);
//printf("Value of x: %d\n", x);
x++;
} while (n != 0 && x <= argc);
close(sockFD);
return 0;
}
The argv array goes from 0 to argc-1 but you are using argv from 3 to argc. Look at the condition on your outer do/while loop.
I created my own ftp server/client (a very simple version) using TCP. There are 5 possible commands: ls-remote, ls-local, get , put and exit. Also, I am using multiprocessing in my server code, to be able to handle multiple clients simultaneously by using fork(). Everything is working perfectly except for one thing that I am noticing: I am having a problem handling broken server connect correctly. For example, if something were to go wrong while the server sends a message, I check if the return value from the send call is less than 0, and then I close the socket, and call exit(-1) to terminate the process; however, this causes my client to hang...
my client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdio.h>
void readDirectory();
void syserr(char* msg)
{ perror(msg);
exit(-1);
}
int main(int argc, char* argv[])
{
int sockfd, portno, n;
struct hostent* server;
struct sockaddr_in serv_addr;
char buffer[256], temp[256];
if(argc < 3) {
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
return 1;
}
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if(!server) {
fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
return 2;
}
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't connect to server");
printf("Connection to %s:%s established. Now awaiting commands...\n\n\n", argv[1], argv[2]);
do{
printf("%s:%s> ", argv[1], argv[2]); //prompt user for command
fgets(buffer, 255, stdin);
n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n')
buffer[n-1] = '\0';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
uint32_t size;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
size = ntohl(size);
int currentSize = 0;
printf("Files at the server: %s\n", argv[1]);
while(currentSize < size){
memset(&buffer[0], 0, sizeof(buffer));
n = recv(sockfd, buffer, 255, 0); // recieve directory from server
if(n < 0) syserr("can't recieve server");
currentSize = currentSize + n;
printf("%s", buffer);
}
}
else if(strcmp(buffer, "ls-local") == 0){ //display files from local directory
printf("Files at the client: \n");
readDirectory();
}
else if(strncmp(buffer, "get ", 4) == 0){ //downlaod file from server
if(strlen(buffer) < 5){ // no file was entered
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t fileSize;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &fileSize, sizeof(fileSize), 0); // get size of file
if(n < 0) syserr("can't receive from server");
fileSize = ntohl(fileSize);
if(fileSize == -1){
printf("%s\n", "File does not exist");
}
else{ // file exists
int totalBytes = 0;
int bytesWritten = 0;
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
memcpy(temp, fileName, strlen(fileName)); //copy filename into temp
temp[strlen(fileName)] = '\0';
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
//receieve the bytes
n = recv(sockfd, buffer, sizeof(buffer), 0);
if(n < 0) syserr("can't receive from server");
//write the bytes
int b = fwrite(buffer, 1, n, fpNew);
if (b < 0)
syserr("error writing file");
if(n == 0){ // error reading on server side
break;
}
totalBytes = n + totalBytes;
bytesWritten = b + bytesWritten;
}
fclose(fpNew);
if(bytesWritten == fileSize) // all bytes read/written to file successfully
printf("Retrieval of file %s: successful.\n", temp);
else
printf("Retrieval of file %s: unsuccessful.\n", temp);
}
else{
syserr("couldnt open file for writing.");
}
}
}
}
else if(strncmp(buffer, "put ", 4) == 0){ // upload file to server
if(strlen(buffer) < 5){
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t commandSize = strlen(buffer);
uint32_t status;
memcpy(temp, buffer, strlen(buffer)); //copy buffer into temp
temp[strlen(buffer)] = '\0';
// get name of file
char *fileName = strtok(temp, " ");
fileName = strtok(NULL, " ");
int bytes;
FILE *fp = fopen(fileName, "r"); // open the file
if(fp){ // file exists and opened
int totalBytes = 0;
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
// get file size
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(sockfd, &size, sizeof(size), 0);
if(n < 0) syserr("can't send to server");
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes...
bytes = fread(buffer, 1, sizeof(buffer), fp); // read bytes fromt he file
if(bytes < 0){
syserr("Error reading the file.");
}
totalBytes = totalBytes + bytes;
//send the bytes
n = send(sockfd, buffer, bytes, 0);
if(n < 0) syserr("can't send to server");
if(bytes == 0){ //error reading
break;
}
}
fclose(fp);
//recieve the final status
n = recv(sockfd, &status, sizeof(status), 0);
if(n < 0) syserr("can't receive from server");
status = ntohl(status);
if(totalBytes == fileSize && status == 1){ // successful on both ends
printf("Upload of file %s: successful.\n", fileName);
}
else{
printf("Upload of file %s: unsuccessful.\n", fileName);
}
}
else{
printf("%s\n", "File does not exist");
}
}
}else if(strcmp(buffer, "exit") == 0){
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
}
else{
if(strcmp(buffer, "exit") != 0)
printf("Error...invalid command.\nValid commands: ls-remote, ls-local, get <filename>, put <filename>, exit\n");
}
}while (strcmp(buffer, "exit") != 0);
printf("Connection to server %s:%s terminated, BYE now!\n", argv[1], argv[2]);
close(sockfd);
return 0;
}
void readDirectory(){
DIR *d = opendir(".");
struct dirent *dir;
if (d)
{
while((dir = readdir(d))!= NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
}
else{
syserr("Error...could not get files from directory.");
}
}
my 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 <dirent.h>
void syserr(char *msg){
perror(msg); exit(-1);
}
void errorHandling(char *msg, int newsockfd){
close(newsockfd);
perror(msg); exit(-1);
}
uint32_t directorySize();
void handle_client(int newsockfd);
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, clt_addr;
socklen_t addrlen;
if(argc < 1) {
fprintf(stderr,"Usage: %s <port>\n", argv[0]);
return 1;
}
if(argc == 1){
argv[1] = "5555";
}
portno = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't bind");
printf("bind socket to port %d...\n", portno);
listen(sockfd, 5);
for(;;){
printf("wait on port %d...\n", portno);
addrlen = sizeof(clt_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
if(newsockfd < 0) syserr("can't accept");
pid_t pid = fork();
if(pid < 0){
syserr("Error can't fork");
}
else if(pid == 0){ // child process
close(sockfd);
handle_client(newsockfd);
close(newsockfd);
break;
}
else{ // parent
close(newsockfd);
continue;
}
}
return 0;
}
uint32_t directorySize(int newsockfd){
DIR *d = opendir(".");
struct dirent *dir;
uint32_t count = 0;
if (d)
{
while((dir = readdir(d))!= NULL)
{
//count++;
count = strlen(dir->d_name) + count + 1;
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
return count;
}
void handle_client(int newsockfd){
// receieve command size from client
uint32_t commandSize;
int n;
char buffer[256];
while(1){
n = recv(newsockfd, &commandSize, sizeof(commandSize), 0); // receive size of command
if(n < 0) errorHandling("can't receive from client", newsockfd);
commandSize = ntohl(commandSize);
//recieve command
n = recv(newsockfd, buffer, commandSize, 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
else buffer[n] = '\0';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
// get the size of the directory
uint32_t size = htonl(directorySize(newsockfd));
n = send(newsockfd, &size, sizeof(size), 0); // send size of directory
if(n < 0) errorHandling("can't send to client", newsockfd);
DIR *d = opendir(".");
struct dirent *dir;
if(d){
while((dir = readdir(d))!= NULL){
memset(&buffer[0], 0, sizeof(buffer));
strcpy(buffer, dir->d_name);
buffer[strlen(buffer)] = '\n';
// send file/folder names
n = send(newsockfd, buffer, strlen(buffer), 0);
if(n < 0)
errorHandling("can't receive from client", newsockfd);
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
}
else if (strncmp(buffer, "get", 3) == 0){ // if command is get
char *fileName = strtok(buffer, " "); // "get"
fileName = strtok(NULL, " "); // the name of the file
FILE *fp = fopen(fileName, "r");
if(fp){ // if file exists
int totalBytes = 0;
int bytes;
// get the size of the file
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(newsockfd, &size, sizeof(size), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes to read...
// read the bytes into the buffer
bytes = fread(buffer, 1, sizeof(buffer), fp);
if(bytes < 0){
errorHandling("Eorror reading bytes on server side", newsockfd);
}
//send the bytes
n = send(newsockfd, buffer, bytes, 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
if(bytes == 0) // error reading file; bytes should have been > 0
break;
totalBytes = totalBytes + bytes;
}
fclose(fp);
}
else{
// tell client file doesnt exist by sending -1
uint32_t dne = htonl(-1);
n = send(newsockfd, &dne, sizeof(dne), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
}
}
else if (strncmp(buffer, "put", 3) == 0){ // upload a file
int totalBytes = 0;
int bytesWritten = 0;
int b = 0;
uint32_t fileSize, status;
n = recv(newsockfd, &fileSize, sizeof(fileSize), 0);// receive the size of file
if(n < 0) errorHandling("can't receive from client", newsockfd);
fileSize = ntohl(fileSize);
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
n = recv(newsockfd, buffer, sizeof(buffer), 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
if(n == 0){ //bad file transfer on client side
break;
}
//write the bytes
b = fwrite(buffer, 1, n, fpNew);
if(b < n){ // error writing to file
break;
}
totalBytes = totalBytes + n; // bytes recived
bytesWritten = bytesWritten + b; //bytes written
}
fclose(fpNew);
if(bytesWritten != fileSize){ // not all bytes written
status = htonl(-1);
}
else{
status = htonl(1);
}
// send the status
n = send(newsockfd, &status, sizeof(status), 0);
if(n < 0) errorHandling("can't send client", newsockfd);
}
else{
errorHandling("could not open file for writing.", newsockfd);
}
}
else{ // command is exit
printf("%s\n", "closing connection");
close(newsockfd); // close the connection
break;
}
}
}
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
That's not sufficient. If n == 0 the peer has closed the connection: you must do likewise and exit the read loop, or indeed possibly the entire process in your case.
This is a multi-client socket program.
When I am trying to run my program the few last recvfrom() do not return any data. But the recvfrom before that have the excess data. Can someone help me how to fix this.
Client:
while (1) {
memset(buff, 0, sizeof(buff));
recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&servaddr,&len);
printf("%s\n", buff);
if (buff[0] == 'U') {
while(1) {
printf("Insert your username: ");
fgets(username,sizeof(username),stdin);
username[strlen(username) - 1] = '\0';
printf("Username chosen is %s\n", username);
// Username Check (Error Check)
if (strlen(username) < 1 || strlen(username) > 16) {
printf("Minimum of 1 and maximum of 16.\n");
continue;
}
for (i = 0; i < strlen(username); i++) {
if (isalnum(username[i]) == 0) {
printf("Username must contain only alphanumeric characters.\n");
j = 0;
break;
}
}
if (j = 0) {
continue;
} else {
break;
}
}
sendto(sockfd,username,strlen(username),0,(const struct sockaddr *)&servaddr,len);
memset(username, 0, sizeof(username));
} else {
break;
}
}
printf("Players:\n");
memset(buff, 0, sizeof(buff));
for (i = 0; i < numplayer; i++) {
printf("BUFF: %s\n", buff);
recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&servaddr,&len);
printf("%s\n", buff);
memset(buff, 0, sizeof(buff));
}
Server:
for (i = 0; i < numplayer; i++) {
while (1) {
memset(mesg,0,sizeof(mesg));
if (recvfrom(connfd[i],mesg,sizeof(mesg),0,(struct sockaddr *)&cliaddr,&len) < 0) {
perror("Recvfrom");
exit(-1);
}
for (j = 0; j < numplayer; j++) {
if (strcmp(username[j], mesg) == 0) {
// Reinitialize buff
memset(buff, 0, sizeof(buff));
check = 1;
break;
}
}
if (check == 1) {
check = 0;
sprintf(buff, "Username already exist!");
if ( sendto(connfd[i],buff,strlen(buff),0,(const struct sockaddr *)&cliaddr,len) < 0 ) {
perror("Sendto");
exit(-1);
}
memset(buff, 0, sizeof(buff));
continue;
} else {
sprintf(buff, "Valid Username!");
if ( sendto(connfd[i],buff,strlen(buff),0,(const struct sockaddr *)&cliaddr,len) < 0 ) {
perror("Sendto");
exit(-1);
}
strcpy(username[i], mesg);
printf("Username of Player %d is %s.\n" ,i + 1,username[i]);
break;
}
}
}
printf("Players:");
for (i = 0; i < numplayer; i++) {
memset(buff, 0, sizeof(buff));
sprintf(buff, "> %s", username[i]);
printf("%s\n", buff);
for (j = 0; j < numplayer; j++) {
if ( sendto(connfd[j],buff,strlen(buff),0,(const struct sockaddr *)&cliaddr,len) < 0 ) {
perror("Sendto");
exit(-1);
}
}
}
There are no 'excess bytes'. recvfrom() returns a length. You are ignoring it. It could also be an EOS (0) or an error indication (-1, see 'errno'). You need to check all those possibilities.
TCP connection may segment the data you send to smaller packets.
If you are receiving data of known size, the receiver have to use a loop to get all the bytes of the payload.
You could find some library to do this job for you if you're new to network programming.
Boost's asio is one that I can think of, but its syntax may be a bit difficult.