0

I am trying to modify some client and server c code so that it takes a user input on the client, send it to the server and the server sends back the corresponding value. I am not very familiar with c programming; therefore, my error is most likely syntax related. Server Code:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int main(int argc, char *argv[])
{
    int listenfd, connfd;
    struct sockaddr_in serv_addr; 

    char sendBuff[1025];
    char from_client[1025];
    time_t ticks; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    while(1)
    {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    recv(connfd, from_client, sizeof(from_client), 0);
    printf("%s", "Letter Recieved\n");
    if(from_client == 't')
    {
        ticks = time(NULL);
            snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, strlen(sendBuff));
    }
    if(from_client == 'n')
    {
        sendBuff == "Marcus Baker";
        send(connfd, sendBuff, sizeof(sendBuff), 0);
    }
    if(from_client == 'i')
    {
        sendBuff == "201604543";
        send(connfd, sendBuff, sizeof(sendBuff), 0);
    }
    if(from_client == 'q')
    {
        return 0;
    }

        close(connfd);
        sleep(1);
     }
}

Client Code:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int main(int argc, char *argv[])
{
    int sockfd, n = 0;
    char letter[1024];
    printf("Enter a Character (t, n, i, q): ");
    scanf("%c",&letter);
    char recvBuff[1024];
    struct sockaddr_in serv_addr; 

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000); 

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    } 

    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
    {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
        }
    } 

    if(n < 0)
    {
        printf("\n Read error \n");
    } 

    int toServer = send(sockfd, letter, sizeof(letter), 0);
    printf("%s", "Letter Sent\n");
    recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    printf("%c", recvBuff);
    
    return 0;
}

Any information would be greatly appreciated.

I have tried several different iteration following different stack overflow guides but none seem to work. When I try to compile both pieces of code, I get warnings about the user input potion of the code, something about scanf expects a char*.

2
  • I suggest you use netcat or socat to simulate either the client or server then fix your code for the peer. When you have one of the peers working then work on the other. Commented Feb 1, 2023 at 4:48
  • As for server you do from_client == 't' but from_client is char [] so you need *from_client == 't' or from_client[0] == 't' Commented Feb 1, 2023 at 5:00

1 Answer 1

1

I suggest you use a known good client, netcat or socat, then fix the server side first:

  1. server: You need to deference from_client to compare against the first letter:
if(*from_client == 't') {

and the server returns the right ting:

$ socat - tcp-connect:localhost:5000
t
Wed Feb  1 00:04:36 2023
  1. server: sendBuff == "Marcus Baker" is a comparison and always false, and you just send send as many bytes as needed instead of the whole buffer:
            strcpy(sendBuff, "Marcus Baker");
            send(connfd, sendBuff, strlen(sendBuff), 0);

and testing it:

n
Marcus Baker
  1. server: sendBuff == "201604543" is a comparison. You have to decide if you want to send it as a string or binary, and if binary if you want a particular encoding (little or big indian). Using a binary and assume the same encoding on both client and server:
            memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
            send(connfd, sendBuff, sizeof(int), 0);

and the result is (note the use of od -t d4 to decode the integer value):

socat - tcp-connect:localhost:5000 | od -t d4
i
0000000   201604543
0000004

Now we know the server works (better) so let's start working on the client.

  1. client: After the client connects it does a read() but server is doing a recv(). Client is expected to write to server so let's just remove this block:
    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
        }
    }

    if(n < 0) {
        printf("\n Read error \n");
    }
  1. server: Now when we send 't' the server responds with time but with a bunch of 0. Going back to server we see it sends the whole buffer so let's fix that:
            int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, n);
  1. client: We still get a bunch of 0 after the time so let's record how much data we get from server and only print that out:
    printf("%s", "Letter Sent\n");
    ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    printf("%.*s", (int) recvLen, recvBuff);

and now the client reports:

Enter a Character (t, n, i, q): t
Letter Sent
Wed Feb  1 00:26:13 2023
  1. client: The data we get for 'i' looks weird:
Enter a Character (t, n, i, q): i
Letter Sent
=
 

This is because it's binary data so we need to decode it:

    if(*letter = 'i') {
        printf("%d", *(int *) recvBuff);
    } else {
        // ...

and the output is now as expected:

Enter a Character (t, n, i, q): i
Letter Sent
201604543
  1. client: 'q' prints doesn't look right:
Letter Sent
808464432

That's because we don't actually expect to get any more data:

    printf("%s", "Letter Sent\n");
    if(*letter == 'q')
        return 0;
  1. server: When client sends a 'q' we return but this leaves the socket in a timeout state. It's better to close it first:
        if(*from_client == 'q') {
            close(connfd);
            return 0;
        }

Here is the programs as changed:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    int sockfd, n = 0;
    char letter[1024];
    printf("Enter a Character (t, n, i, q): ");
    scanf("%c",&letter);
    char recvBuff[1024];
    struct sockaddr_in serv_addr;

    if(argc != 2) {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    }

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Error : Could not create socket \n");
        return 1;
    }

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000);

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0) {
        printf("\n inet_pton error occured\n");
        return 1;
    }

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\n Error : Connect Failed \n");
        return 1;
    }

    int toServer = send(sockfd, letter, sizeof(letter), 0);
    printf("%s", "Letter Sent\n");
    if(*letter == 'q')
        return 0;
    ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    if(*letter = 'i') {
        printf("%d", *(int *) recvBuff);
    } else {
        printf("%.*s", (int) recvLen, recvBuff);
    }
}

server.c:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>

int main(int argc, char *argv[]) {
    int listenfd, connfd;
    struct sockaddr_in serv_addr;

    char sendBuff[1025];
    char from_client[1025];
    time_t ticks;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000);

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    listen(listenfd, 10);

    for(;;) {
        connfd = accept(listenfd, NULL, NULL);

        recv(connfd, from_client, sizeof(from_client), 0);
        printf("%s", "Letter Recieved\n");
        if(*from_client == 't') {
            ticks = time(NULL);
            int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, n);
        }
        if(*from_client == 'n') {
            strcpy(sendBuff, "Marcus Baker");
            send(connfd, sendBuff, strlen(sendBuff), 0);
        }
        if(*from_client == 'i') {
            memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
            send(connfd, sendBuff, sizeof(int), 0);
        }
        if(*from_client == 'q') {
            return 0;
        }
        close(connfd);
        sleep(1);
    }
}
  1. (not fixed) I suggest you extract the shared port number and store in a header file that you can include in both client and server. For example:
#define SERVER_PORT 5000

Then use that constant instead of hard-coding the magic value 5000.

  1. (not fixed) Audit all calls to ensure you check the return value and handle errors. Failing to do so will waste time.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.