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