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
/* 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;
}