一个简易的win下的ipv6 socket编程,读取配置文件,创建线程,连接服务器,用于测试多并发情况下服务器运行状况
login.c
#include<stdio.h>
#include<stdlib.h>
#include <windows.h> // for HANDLE
//#include<pthread.h>
#include<string.h>
#include <time.h>
//#include<netinet/in.h>
//#include<sys/types.h>
//#include<sys/socket.h>
#define STACK_SIZE 64*1024
#pragma pack(1)
#include "login.h"
FILE * fp2=NULL;
void *loginthread( void * arg )
{
USER_INFO *user = (USER_INFO *)arg;
connect_server_ipv6(user);
free(arg);
return ((void *) 1);
}
int main(void)
{
FILE * fp = NULL;
char info[272] = "";
USER_INFO *pinfo;
HANDLE hThread;
DWORD IDThread;
char buf[128];
//pthread_t pid;
int n = 0;
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
//printf ( "\007The current date/time is: %s", asctime (timeinfo) );
memset(buf, 0, sizeof(buf));
strftime(buf, 80, "begintime:%I:%M:%S\n", timeinfo);
printf("begintime:%s", buf);
fp2=fopen("time.txt","w+");
if(NULL==fp2)
{
return-1;
}
fwrite ( buf, strlen(buf), 1 , fp2 );
fp = fopen( "user.txt" , "r" );
if( fp == NULL ) return -1;
while( fgets( info, 63, fp ) != NULL )
{
if (n == 100)
break;
pinfo = ( USER_INFO * )malloc( sizeof( USER_INFO ) );
memset( pinfo, 0, sizeof( USER_INFO ) );
sscanf( info, "%s%s", pinfo->username, pinfo->password );
//printf("username:%s password:%s\n", pinfo->username, pinfo->password);
hThread = CreateThread(NULL, STACK_SIZE, (LPTHREAD_START_ROUTINE)loginthread, ( void * )pinfo, // pass config
STACK_SIZE_PARAM_IS_A_RESERVATION, &IDThread);
if (hThread == NULL)
{
printf("Create Thread failed:n:%d\n", n);
return -1;
}
n++;
//pthread_create( &pid, NULL, loginthread, ( void * )pinfo );
}
printf("%d",n);
#if 0
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s",asctime (timeinfo));
fwrite ( buf, sizeof(buf), 1 , fp2 );
#endif
getchar();
CloseHandle(hThread);
return 0;
}
login.h
#ifndef __LOGIN_H__
#define __LOGIN_H__
#pragma pack(1)
typedef struct
{
char username[256];
char password[16];
} USER_INFO;
struct tcp_keepalive
{
ULONG onoff;
ULONG keepalivetime;
ULONG keepaliveinterval;
};
int connect_server_ipv6(USER_INFO *user);
#endif //__LOGIN_H__
win32client_ipv6.c
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <IPHlpApi.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
extern FILE * fp2;
#pragma comment(lib,"ws2_32.lib")
#include "login.h"
#define NS_INT16SZ 2
#define NO_FLAGS_SET 0
#define IPV6_SERVADDR "::1"
#define IPV6_PORT 2000
#define MAXDATASIZE 200
#define NS_INADDRSZ 4
#define NS_IN6ADDRSZ 16
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
int inet_pton4(const char *src, unsigned char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0')
{
const char *pch;
if ((pch = strchr(digits, ch)) != NULL)
{
unsigned int new = *tp * 10 + (pch - digits);
if (new > 255)
return (0);
*tp = new;
if (! saw_digit)
{
if (++octets > 4)
return (0);
saw_digit = 1;
}
}
else if (ch == '.' && saw_digit)
{
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
}
else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
int inet_pton6(const char *src, unsigned char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
unsigned int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0')
{
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL)
{
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':')
{
curtok = src;
if (!saw_xdigit)
{
if (colonp)
return (0);
colonp = tp;
continue;
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
{
tp += NS_INADDRSZ;
saw_xdigit = 0;
break; /* '\0' was seen by inet_pton4(). */
}
return (0);
}
if (saw_xdigit)
{
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
}
if (colonp != NULL)
{
/* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */
const int n = tp - colonp;
int i;
for (i = 1; i <= n; i++)
{
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
void keepalive(int sfd)
{
ssize_t n;
char keepalivemessage[5];
memset(keepalivemessage, 0, sizeof(keepalivemessage));
keepalivemessage[0] = 0x3;
*((int *)&keepalivemessage[1]) = htonl(5);
n = send(sfd, keepalivemessage, 5, 0);
// FIXME: check return value.
//ssize_t write(int listening_socket, const void *buf, size_t count);
if (n < 0)
{
// failed
}
else
{
#ifdef DEBUG
fprintf(stdout,
"[%d]Heartbeat Send %ld bytes back, fd:%d.\n",
getpid(), n, fd);
#endif
}
}
int connect_server_ipv6(USER_INFO *user)
{
WSADATA Data;
SOCKADDR_IN6 destSockAddr;
SOCKET destSocket;
unsigned long destAddr;
int status;
int recvbytes;
char str[MAXDATASIZE];
char tempbuf[MAXDATASIZE];
char buf[128];
int lenstr;
time_t rawtime;
struct tm * timeinfo;
/* initialize the Windows Socket DLL */
status = WSAStartup(MAKEWORD(1, 1), &Data);
if (status != 0)
printf("ERROR: WSAStartup unsuccessful\n");
/* create a socket */
destSocket = socket(AF_INET6, SOCK_STREAM, 0);
if (destSocket == INVALID_SOCKET)
{
printf("ERROR: socket unsuccessful\n");
status = WSACleanup();
if (status == SOCKET_ERROR)
printf("ERROR: WSACleanup unsuccessful\n");
return (1);
}
int keepAlive = 1; // 开启keepalive属性. 缺省值: 0(关闭)
setsockopt(destSocket, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
struct tcp_keepalive keepin;
struct tcp_keepalive keepout;
keepin.keepaliveinterval=5000;//3000;//15s没有数据就开始发送探测包
keepin.keepalivetime=25000;//15000;//每隔30s发送一次探测包,发10次(默认)
keepin.onoff=1;
DWORD dwActualBytesReturned = 0;
WSAIoctl(destSocket,SIO_KEEPALIVE_VALS,&keepin,sizeof(keepin),&keepout,sizeof(keepout),&dwActualBytesReturned,NULL,NULL);
/*memset destSockAddr*/
memset(&destSockAddr, 0, sizeof(SOCKADDR_IN6));
/* specify the address family as Internet */
destSockAddr.sin6_family = AF_INET6;
/* specify the port portion of the address */
destSockAddr.sin6_port = htons(IPV6_PORT);
/* addr */
inet_pton6(IPV6_SERVADDR, (char *)&destSockAddr.sin6_addr);
//printf("Trying to connect to IPv6 Address: %s\n", IPV6_SERVADDR);
/* connect to the server */
status = connect(destSocket, (SOCKADDR *) & destSockAddr, sizeof(destSockAddr));
if (status == SOCKET_ERROR)
{
printf("ERROR: connect unsuccessful\n");
status = closesocket(destSocket);
if (status == SOCKET_ERROR)
printf("ERROR: closesocket unsuccessful\n");
status = WSACleanup();
if (status == SOCKET_ERROR)
printf("ERROR: WSACleanup unsuccessful\n");
return (1);
}
printf("Connected...\n");
if (send(destSocket, (char *)user, sizeof(USER_INFO), 0) == -1) //发送
{
printf("send wrong !\n");
close(destSocket);
return 1;
}
fprintf(stdout, "send:%d bytes\n", sizeof(USER_INFO));
for (;;)
{
recvbytes = recv(destSocket, str, MAXDATASIZE, 0); //接收
if (recvbytes < 0)
{
{
printf("recv wrong !\n");
break;
}
}
else if (recvbytes == 0)
{
fprintf(stdout, "%s\n", "recvbytes=0");
break;
}
else
{
str[recvbytes] = '\0';
fprintf(stdout, "received: %d bytes\n", recvbytes);
/* keepalive */
//keepalive(destSocket);
}
}
close(destSocket);
return 0;
}
Makefile
# This makefile builds client_ipv6 using the mingw environment.
EXE = ipv6_login_client.exe
HEADERS = login.h
OBJS = win32client_ipv6.o login.o
WARNS = -W -Wall
CC = gcc
CFLAGS = -g -O2 ${WARNS}
all : ${OBJS}
${CC} -o ${EXE} ${OBJS} -lwsock32 -lws2_32
clean :
rm -f *.o *.exe *.bak
%.o : %.c ${HEADERS}
${CC} -c $< -o $@
编译需要在win下面的mingw环境中,需要在当前目录下新建user.txt,格式如下
xiaoming 123
xiaowang abc
xiaoli hello
xiaoping 666
然后运行编译生成的ipv6_login_client.exe和服务端相连接。