###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网络编程