/*****************************************************************************************
UDP客户端程序
文件:udpclient.h
功能:udp客户端程序
平台:VS2008
*****************************************************************************************/
#ifndef _UDPCLIENT_H
#define _UDPCLIENT_H
//****************************************************************************************
void UdpClientTest(void);
int UdpClientInit(void);
void UdpClientClose(void);
int UdpClientSend (const char *SdData , int SdLength);
int UdpClientRecv (char *SdData , int SdLength , int timeout);
int UdpClientRecvs(char *SdData , int SdLength , int timeout);
//****************************************************************************************
#endif
/*****************************************************************************************
UDP客户端程序
文件:udpclient.c
功能:udp客户端程序
平台:VS2008
编者:张永辉 2013年3月19日
添加: 添加UdpClientRecvs函数 2013年4月2日
*****************************************************************************************/
#include
#pragma comment(lib,"ws2_32")
#include
#include
#include
#include "udpclient.h"
//全局变量
SOCKET static sSocket = (SOCKET)NULL;
int static isOpend = 0; //连接是否已经关闭 ==0已经关闭
//int static SerThreadShuedClose = 0; //服务线程是否需要关闭 ==0不需要
static char * ServerIP = "10.169.66.205"; //服务器IP Port
u_short static ServerPORT = 60012;
static struct sockaddr_in saddr; //创建地址结构,与IP Port相对应
/*****************************************************************************************
测试函数
*****************************************************************************************/
void UdpClientTest(void)
{
char rev[200+1];
int num;
int cnt = 10;
//初始化
if(UdpClientInit()!=0)
{ return; }
//收发数据
while (cnt--)
{
//发送数据
UdpClientSend("zhangyonghui",12);
printf("Send:zhangyonghui\n");
//接收数据
num = UdpClientRecv(rev,200,2000);
rev[num] = '\0';
printf("Rev Form Host:%s\n",rev);
getchar();
}
//关闭连接
UdpClientClose();
}
/*****************************************************************************************
返回: 0 成功,可以收发字节了
1 加载库失败
2 创建套接字失败
3 连接到服务器失败
4 已经初始化过了,无需要再次初始化
*****************************************************************************************/
int UdpClientInit(void)
{
int err;
WSADATA wsaData;
WORD sockVersion;
if(isOpend==1)
{ return 4; }
//加载winsock库
sockVersion = MAKEWORD(2,2); //使用2.2版本
err = WSAStartup(sockVersion,&wsaData); //申请使用SOCKET,返回0表示成功,才可以使用其库函数。
if(err!=0)
{ isOpend = 0;
return 1;
}
//创建socket
sSocket = socket( AF_INET, //internetwork: UDP, TCP, etc
SOCK_DGRAM, //网络协议类型,SOCK_DGRAM代表UDP协议,SOCK_STREAM代表TCP协议
IPPROTO_UDP); //protocol 指定网络地址族的特殊协议,目前无用,赋值0即可
if(sSocket==INVALID_SOCKET) //INVALID_SOCKET表示创建失败
{ WSACleanup();
isOpend = 0;
return 2;
}
saddr.sin_family = AF_INET; //AF_INET指定为TCP/IP协议族的套接字
saddr.sin_port = htons(ServerPORT); //指明端口号 htons??
//saddr.sin_addr.s_addr = htonl(INADDR_ANY); //无论哪个网段的客户都能与其通讯。(与下句互斥)
saddr.sin_addr.S_un.S_addr = inet_addr(ServerIP); //固定IP,inet_addr()将字符串IP转换成整行IP
//连接成功,connect返回0;失败则返回SOCKET_ERROR
err = connect(sSocket,(struct sockaddr *)&saddr,sizeof(saddr));
if(err == SOCKET_ERROR)
{ closesocket(sSocket);
WSACleanup();
isOpend = 0;
return 5;
}
isOpend = 1;
return 0;
}
//关闭客户端
void UdpClientClose(void)
{
if(isOpend==0)
{ return; }
closesocket(sSocket); //关闭一个描述符为s套接字
WSACleanup(); //最后一步:解除与Socket库的绑定并且释放Socket库所占用的系统资源
isOpend = 0;
}
/*****************************************************************************************
发送数据函数
参数: *SdData 数据指针
SdLength 数据长度
返回:0 发送失败 或发送了0个字节
n 发送的字节数。
*****************************************************************************************/
int UdpClientSend(const char *SdData , int SdLength)
{
int err;
if(isOpend==0)
{ return 0; }
err = sendto(sSocket,SdData,SdLength,0,(VOID*)&saddr,sizeof(saddr));
if (err <0 )
{ err = 0;
}
return err;
}
/*****************************************************************************************
接收数据函数
参数: *SdData 数据指针
SdLength 数据长度
timeout 超时时间,毫秒
返回:0 接收失败 或接收了0个字节
n 接收的字节数。
*****************************************************************************************/
int UdpClientRecv(char *SdData , int SdLength , int timeout)
{
int err = -1;
int addrlen = sizeof(saddr);
//超时接收需要的变量
struct timeval tv;
fd_set readfds;
if(isOpend==0)
{ return 0; }
//初始化等待时间
tv.tv_sec = timeout/1000; //秒
tv.tv_usec = timeout%1000; //微秒
FD_ZERO(&readfds);
FD_SET(sSocket, &readfds);
//在此函数内进行等待
select(sSocket+(SOCKET)1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(sSocket, &readfds))
{ //从客户端接收消息
err=recvfrom(sSocket,SdData,SdLength,0,(struct sockaddr*)&saddr,&addrlen);
//recv(sSocket,ReData,ReLength,0);使用此函数接收也可以
}
if (err <0 )
{ err = 0; }
return err;
}
/*****************************************************************************************
接收数据函数
参数: *SdData 数据指针
SdLength 数据长度
timeout 超时时间,毫秒
返回:0 接收失败 或接收了0个字节
n 接收的字节数。
说明:UdpClientRecv 是接收一个数据包。若连续发了2包数据,则调用一次只能收一包。
UdpClientRecvs 是接收在此时刻之前的收到的所有数据包。可能有多个包。
*****************************************************************************************/
int UdpClientRecvs(char *SdData , int SdLength , int timeout)
{
int cnt; //单次接收到的数据
int unm = 0; //总共接收到的数据
cnt = UdpClientRecv(SdData,SdLength,timeout);
unm = cnt;
while(cnt!=0)
{
if(SdLength - unm < 0)
{ //没有空间了,退出
break;
}
cnt = UdpClientRecv(&SdData[unm],SdLength - unm,1);
unm += cnt;
//直到没有数据来了,才退出
if(cnt<=0)
{
break;
}
}
return unm;
}