SocketFrame.cpp:
#include "StdAfx.h"
#include "SocketFrame.h"
#include "ws2tcpip.h"
#include "mstcpip.h"
CSocketFrame::CSocketFrame(void)
{
}
CSocketFrame::~CSocketFrame(void)
{
}
/********************************************************
函数名:set_address
输入参数:char * hname:主机名 or 点分十进制表示的IP地址
char * sname:端口号
struct sockaddr_in * sap:以sockaddr_in结构存储的地址(输出参数)
char * protocol:字符串形式描述的协议类型,如"tcp"
输出参数:0表示成功,1表示失败。
功能:根据给定的主机名或点分十进制表示的IP地址获得以sockaddr_in结构存储的地址
*********************************************************/
int CSocketFrame::set_address(char * hname, char * sname, struct sockaddr_in * sap, char * protocol)
{
struct servent *sp;
struct hostent *hp;
char *endptr;
unsigned short port;
unsigned long ulAddr = INADDR_NONE;
//对地址结构socketaddr_in初始化为0,并设置地址族为AF_INET
memset( sap,0, sizeof( *sap ) );
sap->sin_family = AF_INET;
if ( hname != NULL )
{
//如果hname不为空,假定给出的hname为点分十进制表示的数字地址,转换地址为sockaddr_in类型
ulAddr = inet_addr(hname);
if ( ulAddr == INADDR_NONE || ulAddr == INADDR_ANY) {
printf("inet_addr 函数调用错误,错误号: %d\n", WSAGetLastError());
//调用错误,表明给出的是主机名,调用gethostbyname获得主机地址
hp = gethostbyname( hname );
if ( hp == NULL ) {
printf("未知的主机名,错误号: %d\n", WSAGetLastError());
return 1;
}
sap->sin_addr = *( struct in_addr * )hp->h_addr;
}
else
sap->sin_addr.S_un.S_addr=ulAddr;
}
else
//如果调用者没有指定一个主机名或地址,则设置地址为通配地址INADDR_ANY
sap->sin_addr.s_addr = htonl( INADDR_ANY );
//尝试转换sname为一个整数
port = (unsigned short )strtol( sname, &endptr, 0 );
if ( *endptr == '\0' )
{
//如果成功则转换为网络字节顺序
sap->sin_port = htons( port );
}
else
{
//如果失败,则假定是一个服务名称,通过调用getservbyname获得端口号
sp = getservbyname( sname, protocol );
if ( sp == NULL ) {
printf("未知的服务,错误号: %d\n", WSAGetLastError());
return 1;
}
sap->sin_port = sp->s_port;
}
return 0;
}
/********************************************************
函数名:start_up
输入参数:无
输出参数:0:成功,1:失败
功能:初始化Windows Sockets DLL,协商版本号
*********************************************************/
int CSocketFrame::start_up(void)
{
WORD wVersionRequested;
WSADATA wsaData;
int iResult;
// 使用 MAKEWORD(lowbyte, highbyte) 宏,在Windef.h 中声明
wVersionRequested = MAKEWORD(2, 2);
iResult = WSAStartup(wVersionRequested, &wsaData);
if (iResult != 0) {
//告知用户无法找到合适可用的Winsock DLL
printf("WSAStartup 函数调用错误,错误号: %d\n", WSAGetLastError());
return 1;
}
// 确认WinSock Dll支持版本2.2
// 注意,如果DLL支持的版本比2.2更高,根据用户调用前的需求,仍然返回2.2版本号,存储于wsaData.wVersion
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
// 告知用户无法找到可用的WinSock DLL.
printf("无法找到可用的Winsock.dll版本\n");
WSACleanup();
return 1;
}
else
printf("Winsock 2.2 dll成功找到\n");
return 0;
}
/********************************************************
函数名:clean_up
输入参数:无
输出参数:0:成功,1:失败
功能:终止Windows Sockets DLL的使用,释放资源
*********************************************************/
int CSocketFrame::clean_up(void)
{
int iResult;
iResult = WSACleanup();
if (iResult == SOCKET_ERROR) {
// WSACleanup调用失败
printf("WSACleanup 函数调用错误,错误号: %d\n", WSAGetLastError());
return 1;
}
else
printf("Winsock dll 释放成功\n");
return 0;
}
/********************************************************
函数名:quit
输入参数:SOCKET s:服务器的连接套接字
输出参数:0:成功,1:失败
功能:关闭套接字,释放dll
*********************************************************/
int CSocketFrame::quit(SOCKET s)
{
int iResult=0;
iResult = closesocket(s);
if (iResult == SOCKET_ERROR){
printf("closesocket 函数调用错误,错误号:%d\n", WSAGetLastError());
return 1;
}
iResult = clean_up();
return iResult;
}
/********************************************************
函数名:tcp_server
输入参数:char * hname:服务器主机名 or 点分十进制表示的IP地址
char * sname:服务端口号
输出参数:创建服务器端流式套接字并配置,0:表示失败
功能:创建流式套接字,根据用户输入的地址和端口号,绑定套接字的服务地址
将其转换为监听状态
*********************************************************/
SOCKET CSocketFrame::tcp_server( char *hname, char *sname )
{
sockaddr_in local;
SOCKET ListenSocket;
const int on = 1;
int iResult = 0;
//为服务器的本地地址local设置用户输入的IP和端口号
if (set_address( hname, sname, &local, "tcp" ) ==1 )
return 0;
//创建套接字
ListenSocket = socket( AF_INET, SOCK_STREAM, 0 );
if (ListenSocket == INVALID_SOCKET) {
printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());
clean_up();
return 0;
}
//设置服务器地址可重用选项
iResult = setsockopt( ListenSocket, SOL_SOCKET, SO_REUSEADDR, ( char * )&on, sizeof( on ));
if ( iResult == SOC