套接字網絡編程基礎(四)

###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網絡編程

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