Skip to content

Instantly share code, notes, and snippets.

@jirihnidek
Last active March 26, 2024 02:53
Show Gist options
  • Save jirihnidek/388271b57003c043d322 to your computer and use it in GitHub Desktop.
Save jirihnidek/388271b57003c043d322 to your computer and use it in GitHub Desktop.
Example of IPv6 TCP client-server application(s) using blocking sockets
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVER_PORT 7002
int main(int argc, char *argv[])
{
int sock_fd = -1;
struct sockaddr_in6 server_addr;
int ret;
char ch = 'a';
/* Arguments could be used in getaddrinfo() to get e.g. IP of server */
(void)argc;
(void)argv;
/* Create socket for communication with server */
sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Connect to server running on localhost */
server_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, "::1", &server_addr.sin6_addr);
server_addr.sin6_port = htons(SERVER_PORT);
/* Try to do TCP handshake with server */
ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("connect()");
close(sock_fd);
return EXIT_FAILURE;
}
/* Send data to server */
ret = write(sock_fd, &ch, 1);
if (ret == -1) {
perror("write");
close(sock_fd);
return EXIT_FAILURE;
}
/* Wait for data from server */
ret = read(sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(sock_fd);
return EXIT_FAILURE;
}
printf("Received %c from server\n", ch);
/* DO TCP teardown */
ret = close(sock_fd);
if (ret == -1) {
perror("close()");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
# Main CMakeFile.txt
# Minimal version of CMake
cmake_minimum_required (VERSION 2.6)
# Build type
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Debug' as none was specified.")
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif ()
# Define project name
project (Client-Server)
# Source code for server
set (server_src server.c)
# Source code for client
set (client_src client.c)
# Compiler flags
if (CMAKE_COMPILER_IS_GNUCC)
set (CMAKE_C_FLAGS "-D_REETRANT -Wall -Wextra -pedantic -Wno-long-long")
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0")
elseif( CMAKE_BUILD_TYPE STREQUAL "Release" )
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNDEBUG -O3 -fno-strict-aliasing")
endif ()
endif (CMAKE_COMPILER_IS_GNUCC)
# Set up verse server executable
add_executable (server ${server_src})
# Set up verse server executable
add_executable (client ${client_src})
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#define CLIENT_QUEUE_LEN 10
#define SERVER_PORT 7002
int main(void)
{
int listen_sock_fd = -1, client_sock_fd = -1;
struct sockaddr_in6 server_addr, client_addr;
socklen_t client_addr_len;
char str_addr[INET6_ADDRSTRLEN];
int ret, flag;
char ch;
/* Create socket for listening (client requests) */
listen_sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if(listen_sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Set socket to reuse address */
flag = 1;
ret = setsockopt(listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if(ret == -1) {
perror("setsockopt()");
return EXIT_FAILURE;
}
server_addr.sin6_family = AF_INET6;
server_addr.sin6_addr = in6addr_any;
server_addr.sin6_port = htons(SERVER_PORT);
/* Bind address and socket together */
ret = bind(listen_sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(ret == -1) {
perror("bind()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
/* Create listening queue (client requests) */
ret = listen(listen_sock_fd, CLIENT_QUEUE_LEN);
if (ret == -1) {
perror("listen()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
client_addr_len = sizeof(client_addr);
while(1) {
/* Do TCP handshake with client */
client_sock_fd = accept(listen_sock_fd,
(struct sockaddr*)&client_addr,
&client_addr_len);
if (client_sock_fd == -1) {
perror("accept()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
inet_ntop(AF_INET6, &(client_addr.sin6_addr),
str_addr, sizeof(str_addr));
printf("New connection from: %s:%d ...\n",
str_addr,
ntohs(client_addr.sin6_port));
/* Wait for data from client */
ret = read(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(client_sock_fd);
continue;
}
/* Do very useful thing with received data :-) */
ch++;
/* Send response to client */
ret = write(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("write()");
close(client_sock_fd);
continue;
}
/* Do TCP teardown */
ret = close(client_sock_fd);
if (ret == -1) {
perror("close()");
client_sock_fd = -1;
}
printf("Connection closed\n");
}
return EXIT_SUCCESS;
}
@Jackey-Huo
Copy link

Thank you sooooooooo much! This IPv6 socket example is the only one I found on the Internet which could run directly!
Thank you so much about the help ;)

@jirihnidek
Copy link
Author

You are welcome.

@emilengler
Copy link

@emilengler
Copy link

Oh sorry, forgot that this wasn't a string. However maybe it is good to add a note

@jirihnidek
Copy link
Author

Yeah, It is very simple example, when client send only one byte (char). Intention of this example is demonstration of system calls that are necessary to use, when you want to create client-server application using TCP (and IPv6). Production code has to be much more complex.

@darkillerr
Copy link

darkillerr commented Mar 18, 2021

If I change the the ipv6 address in clinet.c line 30 ( inet_pton(AF_INET6, "::1", &server_addr.sin6_addr); ) to another one, such as fe80::f716:3eff:fe90:a0b1 ( I'm sure that [fe80::f716:3eff:fe90:a0b1]:port_num is on listening), then I run the client program, I get an error: "Network is unreachable".
It seems to be the same as the "curl" command using an ipv6 address but without specified interface ( --interface eth0 ).

Do you have any idea? Thanks

@jirihnidek
Copy link
Author

If I change the the ipv6 address in clinet.c line 30 ( inet_pton(AF_INET6, "::1", &server_addr.sin6_addr); ) to another one, such as fe80::f716:3eff:fe90:a0b1 ( I'm sure that [fe80::f716:3eff:fe90:a0b1]:port_num is on listening), then I run the client program, I get an error: "Network is unreachable".
It seems to be the same as the "curl" command using an ipv6 address but without specified interface ( --interface eth0 ).

Do you have any idea? Thanks

It looks like that you have several (at least two) NICs with IPv6 addresses. Maybe your IPv6 routing is not set correctly.

Jiri

@darkillerr
Copy link

If I change the the ipv6 address in clinet.c line 30 ( inet_pton(AF_INET6, "::1", &server_addr.sin6_addr); ) to another one, such as fe80::f716:3eff:fe90:a0b1 ( I'm sure that [fe80::f716:3eff:fe90:a0b1]:port_num is on listening), then I run the client program, I get an error: "Network is unreachable".
It seems to be the same as the "curl" command using an ipv6 address but without specified interface ( --interface eth0 ).
Do you have any idea? Thanks

It looks like that you have several (at least two) NICs with IPv6 addresses. Maybe your IPv6 routing is not set correctly.

Jiri

Thanks for replying. After I checked my IPv6 routing, I think what you said is probably rigth.

@nageshshamnur
Copy link

@darkillerr: can you tell me how you overcame the problem. Even i am facing similar problem with respect to routes. I have more than one interface which has IPv6 address and i am not able to connect using any of these interface. Thanks.

@carsonaj
Copy link

Thank you so much this was very helpful!

@Kay-Linnnn
Copy link

@darkillerr hey, I got the same problem, can you tell me how you fixed this? Thanks.

@Kay-Linnnn
Copy link

@nageshshamnur Finally, I changed this by using global address(as I did with link-local address previously), and it works now. I am confused with the link connect, not sure how to tell whether they are local-linked between two computers, actually I am using gateway.

@AniketMohan
Copy link

Hey can you tell me how to use send() with this. BTW Thanks its awesome

@jirihnidek
Copy link
Author

jirihnidek commented Dec 17, 2021

Hi @AniketMohan,
I have another gists. The send() is used e.g. in this: https://gist.github.com/jirihnidek/9235597. It is maybe more complicated than necessary (it explains punch holing into firewall), but basic trick is that you probably have to use UDP and you have to call connect() before using send(). Without connect() you have to use sendto().

@mcuprojects
Copy link

Hey, thanks for the example! Special thanks for using a good coding style :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment