套接字网络编程基础(四)

###WinSock编程

##WinSock相关介绍

Winsock

##注意事项

Winsock 应用程序要做的第一件事,就是必须首先调用WSAStartup()函数对Winsock进行初始化。初始化也称为注册。注册成功后,才能调用其他的Winsock API函数

int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData );

参数wVersionRequested:指定应用程序所要使用的WinSock规范的最高版本。主版本号在低字节,辅版本号在高字节
参数lpWSAData:是一个指向WSADATA结构变量的指针,用来返回WinSock API实现的细节信息

##Winsock C/S编程实例

###客户机

#include <WinSock2.h>//套接字头文件
#include <string.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")//连入库文件
//默认端口号
#define PROTOPORT 5188

//默认主机名称
char *localhost = "localhost";

int main(int argc,char *argv[])
{
	struct hostent *ptrh;//指向主机列表中一个条目的指针
	struct sockaddr_in servaddr;//服务器ip地址相关信息
	SOCKET sockfd;//连接套接字
	int port;//默认端口
	char *host;//服务器主机名指针
	int n;//读取的字符数
	char buf[1000];//缓冲区,接受服务器发来的数据
	
	WSADATA wsaData;//保存WinSock的注册的结果
	WSAStartup(MAKEWORD(2,2),&wsaData);//WinSock的注册

	memset((char *)&servaddr,0,sizeof(servaddr));//清空sockaddr结构
	servaddr.sin_family = AF_INET;//设置internet协议簇
	//检查命令行参数,如果有,就抽取端口号;否则使用默认值
	if(argc > 2)
		port = atoi(argv[2]);
	else
		port = PROTOPORT;
	if(port > 0)
		servaddr.sin_port = htons((u_short)port);
	else
	{
		printf("bad port number %s\n",argv[2]);
		return 1;
	}
	//检查主机参数并指定主机名
	if(argc > 1)
		host = argv[1];
	else
		host = localhost;

	ptrh = gethostbyname(host);//从服务器主机名得到相应的ip地址
	//检查主机名是否有效
	if((char *)ptrh == NULL)
	{
		printf("invalid host:%s\n",host);
		return 1;
	}
	memcpy(&servaddr.sin_addr,ptrh -> h_addr,ptrh ->h_length);//设置servaddr相关信息
		
	sockfd = socket(AF_INET,SOCK_STREAM,0);//创建流式套接字
	if(sockfd == INVALID_SOCKET)//判断创建成功
	{
		printf("socket creation failed:%d\n",WSAGetLastError());//错误值的获取
		return 1;
	}
	//连接服务器并判断是否连接成功
	if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) == SOCKET_ERROR)
	{
		printf("socket connect failed:%d\n",WSAGetLastError());//10.
		return 1;
	}

	memset((char *)&buf,0,sizeof(buf));//将缓冲区置空
	n = recv(sockfd,buf,sizeof(buf),0);//n为服务器发送数据的字节大小
	while(n > 0)//循环读取数据
	{
		printf("%s\n",buf);
		memset((char *)&buf,0,sizeof(buf));//12.
		n = recv(sockfd,buf,sizeof(buf),0);
	}
	closesocket(sockfd);//关闭套接字
	WSACleanup();//撤销注册
	return 0;
}

服务器


/****************************************
*
*循环监听,连接客户机后发送当前连接的人数
*
****************************************/
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "wsock32.lib")

#define PROTOPORT 5188//默认端口号

#define QLEN 6//最大连接人数

int visits = 0;//连接人数

int main(int argc ,char * argv[])
{
	//注册socket,使用winsock版本2
	WSAData wsa;
	WORD version=MAKEWORD(2,2);
	WSAStartup(MAKEWORD(2,2),&wsa);

	struct hostent * ptrh;//主机信息
	struct sockaddr_in servaddr;//服务器ip地址
	struct sockaddr_in clientaddr;//客户机ip地址
	SOCKET listenfd;//监听套接字
	SOCKET clientfd;//服务器套接字
	int port;//端口号
	int alen;//记录sockaddr_in长度
	char buf[1000];//信息缓冲区

	memset((char*) & servaddr, 0 ,sizeof(servaddr));//将ip地址清空
	servaddr.sin_family = AF_INET;//协议族为AF_INET
	servaddr.sin_addr.s_addr = INADDR_ANY;//服务器ip地址为默认
	
	//cmd模式得到端口信息
	if(argc > 1)
		port = atoi(argv[1]);
	else 
		port =PROTOPORT;
	if(port > 0)
		servaddr.sin_port = htons((u_short)port);
	else{
		fprintf(stderr," bad port number %s \n",argv[1]);
		exit(1);
	}
	//创建监听套接字
	listenfd = socket(AF_INET, SOCK_STREAM,0);
	//判断是否创建成功
	if(listenfd == INVALID_SOCKET){
		printf("socket creation filed %d\n",WSAGetLastError());
		exit(1);
	}
	//将监听套接字绑定主机ip地址
	if(bind(listenfd,(struct sockaddr *) &servaddr ,sizeof(servaddr)) < 0){
		printf(" bind filed %d\n",WSAGetLastError());
		exit(1);
	}
	//开始监听,并指定监听套接字请求队列长度
	if(listen(listenfd,QLEN) < 0)
	{
		printf(" listen filed %d\n",WSAGetLastError());
		exit(1);
	}
	//循环接受处理客户机的连接请求
	while(1)
	{
		alen = sizeof(clientaddr);//记录客户机sockaddr_in长度
		//接受客户机连接请求,并生成响应套接字
		if((clientfd = accept(listenfd,(struct sockaddr *) & clientaddr,&alen))<0){
			fprintf(stderr," accept filed\n");
			exit(1);
		}
		visits++;//连接人数自加
		sprintf(buf,"this server has ben contacted %d time \n" ,visits);//处理信息
		send(clientfd,buf,strlen(buf),0);//发送数据
		closesocket(clientfd);//关闭响应套接字
	}
WSACleanup();//撤销注册
	return 0;
}

##P2P模式编程实例

#include <WinSock2.h>//套接字头文件
#include <string.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")//连入库文件


int main(int argc,char *argv[])
{
	WSADATA wsaData;//保存WinSock的注册的结果

	if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)//WinSock的注册
	{
		printf("Failed to load winsock.\n");
		return -1;
	}

	struct sockaddr_in daddr ,saddr, cmpaddr;//对方信息、本机信息、获取信息结构体
	int sockfd;//错误信息
	char buffer[1000];//缓冲区
	int addrlen, n;

	//检查命令行参数
	if(argc != 5)
	{
		printf("用法 %s 目的IP 目的端口  源IP  源端口\n",argv[0]);
		exit(0);
	}
	//创建套接字
	if((sockfd = socket(AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
	{
		printf("sockfd error %d\n",WSAGetLastError());
		exit(1);
	}
	//为结构体各字段赋值
	addrlen = sizeof(struct sockaddr_in);
	memset(&daddr, 0, addrlen);
	daddr.sin_family = AF_INET;
	daddr.sin_port = htons(atoi(argv[2]));
	if(inet_pton(AF_INET, argv[1],&daddr.sin_addr) <= 0)
	{
		printf("dest inet_pton error %d\n",WSAGetLastError());
		exit(1);
	}
	//为结构体各字段赋值
	addrlen = sizeof(struct sockaddr_in);
	memset(&saddr, 0, addrlen);
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(atoi(argv[4]));
	if(inet_pton(AF_INET, argv[3],&saddr.sin_addr) <= 0)
	{
		printf("source inet_pton error %d\n",WSAGetLastError());
		exit(1);
	}
	//绑定地址
	if(bind(sockfd,(struct sockaddr *)&saddr,addrlen) == SOCKET_ERROR)
	{
		printf("bind error %d\n",WSAGetLastError());
		exit(1);
	}
	//从标准输入获得字符串,并发送给目标地址
	memset(buffer, '\0', sizeof(buffer));
	if(fgets(buffer,1024,stdin) == NULL) exit(0);
	if(sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr *)&daddr, addrlen) == SOCKET_ERROR)
	{
		printf("SENDTO ERROR %d ",WSAGetLastError());
		exit(2);
	}
	//接受信息并显示
	while(1)
	{
		n = recvfrom(sockfd,buffer,1024,0,(struct sockaddr *)&cmpaddr,&addrlen);//接受消息,cmpaddr为出口变量
		if(n <0)
		{
			if(WSAGetLastError() == WSAEWOULDBLOCK)
				printf("recvfrom timeout error: %d\n",WSAGetLastError());
			else
				printf("recvfrom error %d\n",WSAGetLastError());
			exit(1);
		}
		else
		{
			if(memcmp(&cmpaddr,&daddr,addrlen)) continue;//判断数据报来源地址是否与保存的地址是否一致
			buffer[n] = 0;
			printf("Received :%s",buffer);
		}
		memset(buffer, '\0', sizeof(buffer));//清空缓冲区
		if(fgets(buffer,1024,stdin) == NULL) exit(0);//从标准输入获得信息并发送给目标地址
		if(sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr *)&daddr, addrlen) == SOCKET_ERROR)
		{
			printf("SENDTO ERROR %d ",WSAGetLastError());
			exit(3);
		}
	}
	closesocket(sockfd);//关闭套接字
	WSACleanup();//注销sock注册
	return 0;
}

//以上内容大部分摘自《网络编程实用教程(第三版)》 编者 段利国 刘金江 倪天伟 叶树华
//侵权必删
//仅供参考
//windows网络编程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章