每次写网络程序都必须编写代码载入和释放winsock库,为了以后方便使用,我们将封装一个CInitSock类来管理Winsock库:
// initsock.h文件
#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
class CInitSock
{
public:
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};
#include"../common/initsock.h"
#include<iostream>
using namespace std;
CInitSock initSock;
int main()
{
SOCKET s = ::socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP);
if (s == INVALID_SOCKET)
{
cout << "创建socket失败!" << endl;
return 0;
}
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(5678);
address.sin_addr.S_un.S_addr = INADDR_ANY;
if (::bind(s, (LPSOCKADDR)&address, sizeof(address)) == SOCKET_ERROR)
{
cout << "绑定套接字失败!" << endl;
return 0;
}
cout << "socket绑定成功,等待客户端连接..." << endl;
char receivedData[1024];
sockaddr_in temp;
int len = sizeof(temp);
while (true)
{
int index = ::recvfrom(s, receivedData, 1024, 0, (sockaddr*)&temp, &len);
if (index > 0)
{
receivedData[index] = ' ';
printf("服务器端接收来自IP为:%s的数据: %s
", ::inet_ntoa(temp.sin_addr), receivedData);
}
}
::closesocket(s);
return 0;
}
部分函数详解:
recvfrom()
本函数用于从(已连接)套接口上接收数据,并捕获数据发送源的地址。
函数原型:
int PASCAL FAR recvfrom( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen);
s:标识一个已连接套接口的描述字。
buf:接收数据缓冲区。
len:缓冲区长度。
flags:调用操作方式。
from:(可选)指针,指向装有源地址的缓冲区。
fromlen:(可选)指针,指向from缓冲区长度值。
返回值:
若无错误发生,recvfrom()返回读入的字节数。如果连接已中止,返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。