IPv6 simple TCP Server demo

TCP Server client implemention in C

* main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h> /* read(), write(), close() */
#include <errno.h>
#include <pthread.h>

#define CLTBUFSZ 256

static int sockfd;

static off_t get_line(FILE *f, char *b) {
    off_t off = 0;

    fgets(b, 255, f);
    while (off < 255 && b[off]!=0x0d && b[off]!=0x0a) {
        off++;
    }
    b[off] = 0x00;
    return off;
}

// Function designed for chat between client and server.
int client_handler(int clt_fd, char *clt_ip)
{
    char buff[CLTBUFSZ];
    FILE *is = fdopen(clt_fd, "r");
    off_t off;
    char body[256];

    if (!is) {return -1;}
    bzero(buff, CLTBUFSZ);

    while (!feof(is)) {
        off = get_line(is, buff);
        if (off < 3) { break; }
        printf("%s\n", buff); /* Print client request message */
    }

    strcpy(buff, "HTTP/1.1 200 OK\r\n");
    send(clt_fd, buff, strlen(buff), 0);
    strcpy(buff, "Date: Sun, 12 May 2024 05:41:07 GMT\r\n");
    send(clt_fd, buff, strlen(buff), 0);
    sprintf(body, "<h1>TCP Server IPv6 demo.</h1><p>Your IP address: %s</p>\n", clt_ip);
    sprintf(buff, "Content-Length: %lu\r\n", strlen(body));
    send(clt_fd, buff, strlen(buff), 0);
    strcpy(buff, "Content-Type: text/html; charset=utf-8\r\n\r\n");
    send(clt_fd, buff, strlen(buff), 0);
    send(clt_fd, body, strlen(body), 0);

    return 0;
}

#define IPv6_CHUNK  \
    *s++ = cvt[ t[i]>>4 ]; \
    *s++ = cvt[ t[i] & 0x0f ]; \
    i++; \
    *s++ = cvt[ t[i]>>4 ]; \
    *s++ = cvt[ t[i] & 0x0f ]; \
    i++

char *inet6_to_s(struct in6_addr addr6) {
    char *s_addr = malloc(40);
    char *s = s_addr;
    uint8_t *t = (uint8_t *)addr6.__in6_u.__u6_addr8;
    int i = 0;
    char cvt[] = "0123456789abcdef";

    IPv6_CHUNK;
    while (i < 16) {
        *s++ = ':';
        IPv6_CHUNK;
    }
    *s = 0x00;
    return s_addr;
}

unsigned short atos(const char s[]) {
    int i;
    unsigned short us = 0;
    for (i = 0; i < 6 && s[i]; i++) {
        if (s[i] < 0x30 || s[i] > 0x3a) {
            break;
        }
        us *= 10;
        us += s[i] - 0x30;
    }
    return us;
}

void *work_rt(void *params) {
    int ret;
    char *s_addr = NULL;
    socklen_t len;
    int connfd;
    struct sockaddr_in6 cli;

    connfd = accept(sockfd, (struct sockaddr *)&cli, &len);
    if (connfd < 0) {
        printf("server accept failed...\n");
        return NULL;
    }

    struct timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    if (setsockopt (connfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout) < 0) {
        printf("setsockopt failed\n");
        return NULL;
    }
    s_addr = inet6_to_s(cli.sin6_addr);
    if (0 == strncmp(s_addr, "0000:0000:0000:0000:0000:0000:0000:0000", 39)) {
        return NULL;
    }
    printf("server accept the client#%d [%s]:%d\n", connfd, s_addr, ntohs(cli.sin6_port));
    ret = client_handler(connfd, s_addr);
    if (ret != 0) {
        printf("client_handler error %d:%s\n", errno, strerror(errno));
    }
    free(s_addr);
    close(connfd);
    return NULL;
}


/*
 * http://[2408:8940:0:974a:368c:700c:????:????]:8080/
 * curl -i "http://\[2408:8940:0:974a:368c:700c:????:????\]:8080"
*/
int main(int argc, char *argv[])
{
    struct sockaddr_in6 servaddr;
    char s_port[6];
    pthread_t t1;

    if (argc < 2) {
        printf("Usage: %s port\n", argv[0]);
        return 0;
    }
    strncpy(s_port, argv[1], 6);

    sockfd = socket(AF_INET6, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed %d:%s\n", errno, strerror(errno));
        return errno;
    }
    printf("server sockfd=%d\n", sockfd);
    /* atexit(clean_handler); */
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin6_family = AF_INET6;
    servaddr.sin6_addr = in6addr_any;
    servaddr.sin6_port = htons(atos(s_port));

    /*
> netstat -ano | findstr 8080
TCP    192.168.0.104:15515    157.148.54.168:8080    ESTABLISHED     24680
TCP    [2408:8940:0:974a:b0db:b3d9:????:????]:17234  [2408:80f1:21:4080::28]:8080  ESTABLISHED     11092
> taskkill /F /PID 11092
> taskkill /F /PID 24680
     */
    if ((bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed:%d:%s\n", errno, strerror(errno));
        return errno;
    }
    printf("Socket bound ipaddr.\n");
    // Now server is ready to listen and verification
    if ((listen(sockfd, 16)) != 0) {
        printf("Listen failed...\n");
        return errno;
    }
    printf("Server listening [::]:%d\n", ntohs(servaddr.sin6_port));

    /* Accept the data packet from client and verification */
    for (;;) {
        pthread_create(&t1, NULL, work_rt, NULL);
        pthread_join(t1, 0);
    }
}

* CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(tcpsvr C)

set(CMAKE_C_STANDARD 90)

add_executable(tcpsvr main.c)

target_link_libraries(tcpsvr pthread)

* Makefile

CC=gcc
CFLAGS=-g -static -Wl,-s,--stack=67108864
TARGETS=tcpsvr
all: ${TARGETS}

${TARGETS}: main.o
	${CC} main.o -lpthread -o $@
main.o: main.c
	${CC} ${CFLAGS} -c main.c -o $@

clean:
	rm -f ${TARGETS} main.o core.*

test:
	./tcpsvr 8080

make

make test

 

windows查看IPv6邻居

netsh interface ipv6 show neighbors

block_clt.c

/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For gethostbyname */
#include <netdb.h>

#include <unistd.h>
#include <string.h>
#include <stdio.h>

int tcp6_connector(const char *node, const char *service) {
	struct addrinfo hints;
	struct addrinfo *result = NULL, *rp;
	int status, sfd;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_INET6;    /* Allow IPv4 or IPv6: AF_UNSPEC */
	hints.ai_socktype = SOCK_STREAM; /* Datagram socket: SOCK_DRGAM */
	hints.ai_flags = 0; /* AI_GETADDRINFO_FLAG; */
	hints.ai_protocol = 0;          /* Any protocol */

	status = getaddrinfo(node, service, &hints, &result);
	if (status != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
		return -1;
	}
	printf("status=%d\n", status);
	for (rp = result; rp != NULL; rp = rp->ai_next) {
		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if (sfd == -1) {
			continue;
		}
		if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
			break;                  /* Success */
		}
		close(sfd);
	}
	if (rp == NULL) {               /* No address succeeded */
		fprintf(stderr, "Could not connect\n");
		return -1;
	}
	freeaddrinfo(result);           /* No longer needed */
	return sfd;
}

int main(int c, char **v)
{
	const char query[] =
		"GET / HTTP/1.0\r\n"
		"Host: www.google.com\r\n"
		"\r\n";
	const char hostname[] = "www.google.com";
	struct sockaddr_in6 sin6;
	struct hostent *h;
	const char *cp;
	int fd;
	ssize_t n_written, remaining;
	char buf[1024];
	
#if 0
	fd = tcp6_connector(hostname, NULL);
	if (fd < 0) {
		fprintf(stderr, "tcp6_connector failed\n");
		return fd;
	}
	printf("fd=%d\n", fd);
#else
	/*
	h = gethostbyname(hostname);
	if (!h) {
		fprintf(stderr, "Couldn't lookup %s: %s", hostname, hstrerror(h_errno));
		return 1;
	}
	if (h->h_addrtype != AF_INET6) {
		fprintf(stderr, "No ipv6 support, sorry.");
		return 1;
	}
	*/

	/* Allocate a new socket */
	fd = socket(AF_INET6, SOCK_STREAM, 0);
	if (fd < 0) {
		perror("socket");
		return 1;
	}

	/* Connect to the remote host. */
	sin6.sin6_family = AF_INET6;
	sin6.sin6_port = htons(80);
	/* sin6.sin6_addr = *(struct in6_addr*)h->h_addr; */
	inet_pton(AF_INET6, "2a00:1450:4028:809::2004", &sin6.sin6_addr);
	
	if (connect(fd, (struct sockaddr*) &sin6, sizeof(sin6))) {
		perror("connect");
		close(fd);
		return 1;
	}
#endif

	/* Write the query. */
	/* XXX Can send succeed partially? */
	cp = query;
	remaining = strlen(query);
	while (remaining) {
		n_written = send(fd, cp, remaining, 0);
		if (n_written <= 0) {
			perror("send");
			return 1;
		}
		remaining -= n_written;
		cp += n_written;
	}

	/* Get an answer back. */
	while (1) {
		ssize_t result = recv(fd, buf, sizeof(buf), 0);
		if (result == 0) {
			break;
		} 
		if (result < 0) {
			perror("recv");
			close(fd);
			return 1;
		}
		fwrite(buf, 1, result, stdout);
	}

	close(fd);
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fareast_mzh

打赏个金币

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值