6

I have just started learning socket programming and am finding it pretty interesting. Currently I am making the server and the client on the same computer and hence I can have the ip address as the loopback address, 127.0.0.1 and everything seems to work fine!!

But now I was thinking of having two computers and doing the thing.. I have the following questions

  1. Say one computer is Server and another is Client. Now, should the server code reside on the server computer and the Client code on the client one?
  2. In the server code when we are providing the ip address for bind(), it should be the ip address of the system that we can find through ipconfig or it should still remain the loopback address?
  3. In the client code, I guess the ip address of the destination should be that of the server computer right??
  4. And the last and the most important thing, HOW DO I CONNECT THE TWO COMPUTERS??

I am attaching the simple server and client message passing code that I started out with. Kindly guide me through the changes that I need to make..

SERVER CODE

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#define MYPORT 3500

int main()
{
    int sockfd;
    int clientfd;
    int bytes_read;
    char buf[100];
    int struct_size;
    struct sockaddr_in my_addr;
    struct sockaddr_in con_addr;
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(MYPORT);
    my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    my_addr.sin_zero[8]='\0';

    bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));

    listen(sockfd,5);
    
    struct_size = sizeof(con_addr);
    clientfd = accept(sockfd, (struct sockaddr*)&con_addr, &struct_size);

    bytes_read = read(clientfd, buf, 100);
    buf[bytes_read] = '\0';
    printf("Message from client:%d is %s \n",clientfd, buf);

    close(sockfd);
    close(clientfd);
}

CLIENT CODE

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<string.h>
#include<stdio.h>

#define DESTPORT 3500

int main()
{

    struct sockaddr_in dest_addr;
    
    int sockfd = socket(AF_INET,SOCK_STREAM,0);

    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(DESTPORT);
    dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    dest_addr.sin_zero[8]='\0';

    connect(sockfd,(struct sockaddr*)&dest_addr, sizeof(struct sockaddr));

    char msg[100];
    printf("Enter you message: ");
    gets(&msg); 
    
    int w = write(sockfd, msg, strlen(msg));
    
    close(sockfd);
    printf("Client Dying.....\n"); 

    return 0;
}
1
  • 1
    One doesn't always seek wisdom from the questions themselves, but your question alone is super-useful, thank you Commented Mar 3, 2024 at 18:11

5 Answers 5

4

1) Correct.

2) On the server side you can bind to 0.0.0.0 which means "all (IPv4) interfaces".

3) Yes, you are right.

4) Most commonly through an Ethernet switch (or a cross-over Ethernet cable but those are harder to find).

Sign up to request clarification or add additional context in comments.

Comments

3

Server should bind to 0.0.0.0 (any) unless you're trying to restrict access (and in that case you should really use a firewall rather than port binding). The correct way is actually:

struct addrinfo *ai, hints = { .ai_flags = AI_PASSIVE };
if (getaddrinfo(0, "1234", &hints, &ai)) goto error;
int fd = socket(ai->ai_family, SOCK_STREAM, 0);
bind(fd, ai->ai_addr, ai->ai_addrlen);

Add some error checking, of course. Replace "1234" with your port number.

6 Comments

Solves my case just the way I wanted it to.. Thanks a ton :-) Can you suggest some good resource to read up about the modern socket programming??
Basically the man pages (or POSIX documentation, here: pubs.opengroup.org/onlinepubs/9699919799/functions/…) for getaddrinfo, getnameinfo, socket, bind, connect, listen, accept, sendto, recvfrom, and select is just about all you need. All the complexity you see in older examples and tutorials is merely legacy baggage and a detriment to IPv6 support and portability.
Why are you not specifying a port anywhere?
Stupid mistake. Fixed it. Of course you could let bind assign you a port number, then use getsockname and getnameinfo to record it and publish it for clients to use.
When you use getaddrinfo() you should always loop through all the results and create one socket per listening address. If you just want to do IPv4 any address for simplicity, there's no reason to use getaddrinfo() in the first place. Your code can lead to surprising situations depending on the system configuration.
|
0

127.0.0.1 is localhost the loopback address for the machine you are currently on. You probably want to change that to a real ip in the client, if you use two separate boxes.

Yes, the client is usually, but not always, on another physical box from the server. You can just run both pieces on omne box if you want

2 Comments

Thank you Sir.. So, I change the ip address in the client code to the ip address of the server machine.. Fine.. But what do I do to the ip address on the server code, here, my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
You should never have to poke at sin_addr.s_addr, etc. manually. This is a bad kind of socket programming from the early 90s that will bring you lots of headaches and make it hard to support IPv6. See my answer for the modern way to bind a socket for listening.
0

1) Say one computer is Server and another is Client. Now, should the server code reside on the server computer and the Client code on the client one??

I don't think I understand this one in the right perspective...lol.If your clientside code is in serverside,how could you allocate any memory lots or invoke stuff on the client computer?

2) In the server code when we are providing the ip address for bind(), it should be the ip address of the system that we can find through ipconfig or it should still remain the loopback address??

what we have on man page:

 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

"bind() assigns the address specified to by addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr. Traditionally, this operation is called "assigning a name to a socket". It is normally necessary to assign a local address using bind() before a SOCK_STREAM socket may receive connections (see accept(2))."

In your case,I suppose,127.0.0.1 is what you are looking for.In a nutshell,the address you talked about is more likely to be the one you set up to server_addr structure.

3) In the client code, I guess the ip address of the destination should be that of the server computer right??

Yes.

4) And the last and the most important thing, HOW DO I CONNECT THE TWO COMPUTERS??

Sounds like a classic chat room application. As far as I know(I am a novice...),UDP(User Datagram Protocol) programming & APIs is worth a shot,probably.If you would like to stick to TCP/IP,two arbitrary computers essentially not connect to each other but both stay a hold with the server and the server will be the cornerstone between them.

What's more,I looked into some socket man page:

 int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

"The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. The addrlen argument specifies the size of addr. The format of the address in addr is determined by the address space of the socket sockfd; see socket(2) for further details."

I think this explains your question in a theoretical manner perfectly.

1 Comment

I m new to socket programming, is this concept correct, provided we can connect the server and client computer together perhaps via a LAN, or WAN, then server and client resides in two separate computers, and the server can yet allocate some memory on the server side computer, for the client.I m thinking its conceptually correct, please but correct me, if I m wrong
0

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

#define PORT 7223  
#define BUFFER_SIZE 1024

void censor(char *message) {
    char *words[] = {"bad", "fail"};
    for (int i = 0; i < 2; i++) {
        char *pos = strstr(message, words[i]);
        while (pos != NULL) {
            memset(pos, '*', strlen(words[i]));
            pos = strstr(pos + strlen(words[i]), words[i]);
        }
    }
}

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    char buffer[BUFFER_SIZE];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("Socket creation failed");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(server_addr.sin_zero), '\0', 8);

    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        exit(1);
    }

    listen(server_fd, 5);
    printf("Server listening on port %d...\n", PORT);

    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd < 0) {
        perror("Accept failed");
        exit(1);
    }

    recv(client_fd, buffer, BUFFER_SIZE, 0);
    printf("Original Message: %s\n", buffer);

    censor(buffer);

    send(client_fd, buffer, strlen(buffer), 0);
    printf("Censored Message Sent: %s\n", buffer);

    close(client_fd);
    close(server_fd);

    return 0;
}



#####client sample
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 7223
#define BUFFER_SIZE 1024

int main() {
    int sock;
    struct sockaddr_in server_addr;
    char buffer[BUFFER_SIZE];

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("Socket creation failed");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(&(server_addr.sin_zero), '\0', 8);

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Connect failed");
        exit(1);
    }

    printf("Enter message: ");
    fgets(buffer, BUFFER_SIZE, stdin);

    send(sock, buffer, strlen(buffer), 0);

    recv(sock, buffer, BUFFER_SIZE, 0);
    printf("Censored Message: %s\n", buffer);

    close(sock);

    return 0;
}

1 Comment

Thank you for contributing an answer! The example code you provide does solve the problem, but there two some things you could do to make the answer even more helpful: first, describe how the example works. There are 4 specific questions asked. A great answer would address each of them, and point out where in the example (if applicable) this question is addressed. The second way to improve the answer would be to strip the example code of things not directly related to the question, e.g. the censor function. Again, thank you for the answer!

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.