Windows Socket+UDP服务器客户端
Winsock
是 Windows下套接字标准
。
1.UDP socket编程:
UDP(用户数据报协议)是一个无连接,不可靠的数据传输,其特点是简单,快捷。相比与TCP,UDP不需要建立连接(不需connect、accept函数),数据发送接收之后,不需要终止连接。基于UDP的程序,避免了TCP运行的开销,在效率与速度上具有更好的表现。
UDP是无连接的,可能会有数据的丢失,延迟,这些需要应用程序自己处理。
2.UDP基本函数:
创建socket:
SOCKET socket (int af, int type, int protocol);
第一个参数af: 表示族地址,网络编程一般使用AF_INET宏。
第二个参数type: 表示连接类型,TCP可选面向连接SOCK_STREAM,UDP数据报SOCK_DGRAM。
第三个参数protocol: 表示协议,在使用AF_INET族地址UDP连接,设为IPPROTO_UDP。
绑定socket:
int bind(SOCKET s, const struct sockaddr *saddr,int namelen);
第一个参数: 需要绑定的socket。
第二个参数: 对应AF_INET,使用struct sockaddr_in包含协议,IP,端口等信息。
第三个参数: 对应AF_INET,使用struct sockaddr_in结构大小。
该函数将socket与协议,IP地址,Port端口号绑定起来,相对于给socket“命名”唯一的标识,这样其他的进程就可以通过这个标识找到这个socket。
发送数据:
int sendto(SOCKET s, const char *buf, int len,
int flags, const struct sockaddr *to, int tolen);
第一个参数: socket为对方的socket。
第二个参数: 发送数据的缓冲区。
第三个参数: 数据缓冲区大小。
第四个参数: 紧急状态,一般这为0。
第五个参数: 可选,对应AF_INET,对方IP,端口等socket地址标识sockaddr_in。
第六个参数: 可选,对应AF_INET,使用sockaddr_in结构大小。
该函数用于UDP发送数据。
接收数据:
int recvfrom(SOCKET s, char *buf, int len,
int flags, struct sockaddr *from, int *fromlen );
第一个参数: socket为对方的socket。
第二个参数: 接收数据的缓冲区。
第三个参数: 数据缓冲区大小。
第四个参数: 紧急状态,一般这为0。
第五个参数: 可选,对应AF_INET,返回对方IP,端口等socket地址标识sockaddr_in。
第六个参数: 可选,对应AF_INET,使用sockaddr_in结构大小。
该函数用于UDP接收数据。
绑定socket:
int bind(SOCKET s, const struct sockaddr *saddr,int namelen);
第一个参数: 需要绑定的socket。
第二个参数: 对应AF_INET,使用struct sockaddr_in包含协议,IP,端口等信息。
第三个参数: 对应AF_INET,使用struct sockaddr_in结构大小。
该函数将socket与协议,IP,端口号绑定起来,相对于给socket“命名”唯一的标识,这样其他的进程就可以通过这个标识找到这个socket。
关闭套接字:
int closesocket(SOCKET s);
参数为socket。
该函数用于关闭套接字。
3.牛刀小试:
先在VC6.0运行服务器程序,再打开一个VC6.0运行客户端程序:
UDPsever服务器等待来自客户端的信息,收到信息后打印出来,然后向客户端发送现在的时间。
UDPclient客户端向服务器发送一个“Hello,server!”信息,然后接收来自服务器的时间信息并打印,重复三次。
运行效果:
UDP客户端程序:
#include
#include
#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsa;
SOCKET serversoc;
SOCKADDR_IN serveraddr;
SOCKADDR_IN peeraddr;
int peer_len=sizeof(peeraddr);
char Recv_buf[64];
//char *Server_IP="127.0.0.1";
char *Send_data="Hello,server!";
int Send_len=strlen(Send_data);
int time_out=2000; //接收超时
int result;
WSAStartup(WINSOCK_VERSION,&wsa); //初始化WS2_32.DLL
//命名协议,IP,端口
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(13);
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(serveraddr.sin_addr.s_addr==INADDR_NONE)
{
printf("不可用地址!\n");
return -1;
}
//创建套接字
serversoc = socket(AF_INET,SOCK_DGRAM,0);
result = setsockopt(serversoc,SOL_SOCKET,SO_RCVTIMEO,(char*)&time_out,sizeof(time_out));
for(int i=0;i<3;i++)
{
//发送数据
result = sendto(serversoc,Send_data,Send_len,0,(SOCKADDR *)&serveraddr,sizeof(serveraddr));
//接收数据
result = recvfrom(serversoc,Recv_buf,64,0,(SOCKADDR *)&peeraddr,&peer_len);
if(result >= 0)
{
Recv_buf[result]= 0;
printf("接收数据为: %s \n",Recv_buf);
}
}
closesocket(serversoc);
WSACleanup();
return 0;
}
UDP服务器程序:
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsa;
WSAStartup(WINSOCK_VERSION,&wsa); //初始化WS2_32.DLL
SOCKET serversoc;
SOCKET clientsoc;
SOCKADDR_IN serveraddr;
SOCKADDR_IN clientaddr;
int client_len = sizeof(clientaddr);
int server_len = sizeof(serveraddr);
char *Send_data;
int Send_len;
char Recv_buf[64];
int result;
time_t nowtime;
//命名协议,IP,端口
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(13);
serveraddr.sin_addr.s_addr = INADDR_ANY;
//创建socket
serversoc = socket(AF_INET,SOCK_DGRAM,0);
//绑定socket
result=bind(serversoc, (SOCKADDR *)&serveraddr, server_len);
if(result==SOCKET_ERROR)
{
printf("套接字绑定失败!\n");
closesocket(serversoc);
return -1;
}
printf("Server is running.....\n");
clientsoc = socket(AF_INET,SOCK_DGRAM,0);
while(1)
{
//接收数据
result = recvfrom(serversoc,Recv_buf,64,0,(SOCKADDR *)&clientaddr,&client_len);
if(result >= 0)
{
Recv_buf[result]= 0;
printf("接收数据为: %s \n",Recv_buf);
//发送数据
nowtime=time(0);
Send_data=ctime(&nowtime);
Send_len=strlen(Send_data);
result = sendto(clientsoc,Send_data,Send_len,0,(SOCKADDR *)&clientaddr,sizeof(clientaddr));
printf("Server is running.....\n");
}
}
closesocket(serversoc);
WSACleanup();
return 0;
}