理论知识我也不说太多了,网络上一百度大把,但可能就是贴部分代码并没开源,所以你拿过去可能就用不了,而我这个就不同了开源分享
运行环境:VS2012 win10 X64
大致步骤为:
包含必要的头文件及库
- 指定需要的SOCKET最高版本
- 创建套接字
- 绑定IP及端口
- 监听
- 连接
- 接收数据
- 发送数据
- 关闭套接字
以下是核心代码
TCP通信
客户机:
int nErrCode=0;
//初始化socket
InitWinSock();
//创建套接字
SOCKET sock=socket(AF_INET,SOCK_STREAM,0);
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(1234);
addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
//连接服务器
nErrCode=connect(sock,
(sockaddr*)&addr,//ip地址
sizeof(sockaddr_in));//ip 地址的大小
if (SOCKET_ERROR==nErrCode)
{
printf("查看是否已启动服务端!\n");
closesocket(sock);
WSACleanup();
system("pause");
return FALSE;
}
char InitName[20]={0};
InitName[0]='@';
printf("起个名字吧");
scanf_s("%s",InitName+1,19);
//发送消息
nErrCode=send(sock,InitName,20,0);
if (SOCKET_ERROR==nErrCode)
{
printf("发送消息失败!%d\n",GetLastError());
}
//双肩线程处理服务端发送回来的数据
CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadProc,(LPVOID)sock,0,0);
char buf[1024]={0};
int nInputSize;
while (true)
{
printf("请输入\n");
scanf_s("%s",buf,1024);
nInputSize=strlen(buf)+1;
nErrCode=send(sock,buf,nInputSize,0);
if (SOCKET_ERROR==nErrCode)
{
printf("发送消息失败\n");
}
}
int nErrcode=0;//错误代码
//创建套接字
SOCKET sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//设置套接字非阻塞模式
unsigned long u1=1; //设置套接字选项
int nRet=ioctlsocket(sock,FIONBIO,&u1);
//初始化ip地址
sockaddr_in addr;
addr.sin_family=AF_INET; //地址家族
addr.sin_port=htons(1234); //端口号 大端到小端
addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//IP地址 本地:127.0.0.1
//取得本地主机名称
//char szHost[MAX_PATH]={0};
//gethostbyname(szHost);
//通过主机名取到地址信息
//HOSTENT *pHost=gethostbuname(szHost);
//绑定套接字
nErrcode=bind(sock, //套接字
(sockaddr*)&addr,// ip 地址
sizeof(sockaddr_in));//ip 地址结构体大小
if (SOCKET_ERROR==nErrcode)
{
printf("ip地址绑定失败");
closesocket(sock); //关闭套接字
WSACleanup(); //释放套接字
}
//监听
nErrcode=listen(sock,
SOMAXCONN);//能够同时连接的最大数目
if (SOCKET_ERROR==nErrcode)
{
printf("监听失败");
goto CloseSock;
}
int nAddrSize=sizeof(sockaddr_in);
while (true)
{
sockaddr_in addrClient;
memset(&addrClient,0,sizeof(sockaddr_in));
addrClient.sin_family=AF_INET;
//连接
SOCKET ClientSocket=accept(sock,
(sockaddr*)&addrClient,
&nAddrSize);
if (INVALID_SOCKET==ClientSocket)
{
continue;
}
NAME PlayName;
PlayName.Sock=ClientSocket;
g_player.push_back(PlayName); //保存连接套接字
//创建线程 结构客户端的消息
CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadProc,(LPVOID)ClientSocket,0,0);
}
return TRUE;
CloseSock:
closesocket(sock);
WSACleanup();
return FALSE;
//1.初始化SOCKET
InitWinSock();
//2.创建套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in addr,addr2;
int n=sizeof(addr2);
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //127.0.0.1
char InitName[20] = { 0 }; //名字
InitName[0] = '@';
printf("%起个名字吧:");
scanf_s("%s", InitName + 1, 19);
//4.发送消息
nErrCode = sendto(sock, InitName, sizeof(InitName), 0,(sockaddr*)&addr,n);
//if (SOCKET_ERROR == nErrCode)
//{
// printf("发送消息失败!%d\n",GetLastError());
//}
//创建线程处理服务端发送回来的数据
// CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)sock, 0, 0);
char buf[1024] = { 0 };
int nInputSize;
while (true)
{
printf("请输入:");
scanf_s("%s", buf, 1024);
nInputSize = strlen(buf) + 1;
nErrCode = sendto(sock, buf, nInputSize, 0,(sockaddr*)&addr,sizeof(addr2));
//if (SOCKET_ERROR == nErrCode)
//{
// printf("发送消息失败\n");
//}
}
//1.初始化OCKET
InitWinSock();
//2.建立Socket
//初始化winSock的动态链接库后 需要在服务器端建立一个监听socket,
//为此可以调用socket()函数来建立这个监听的socket,并定义通信协议
SOCKET sSocket;
sSocket = socket(AF_INET, //PF_INET(AF_INET)
SOCK_DGRAM, //Socket的类型 (SOCK_STREAM(TCP),SOCK_DGRAM(UDP))
IPPROTO_UDP);
//通信协议(如果使用者不指定则设为0)
if (INVALID_SOCKET == sSocket)
{
printf("创建套接字失败! 错误码:%d", WSAGetLastError());
WSACleanup(); //释放服务
return false;
}
//3.定义服务器地址
sockaddr_in service; //服务器套接字地址
service.sin_family = AF_INET;
ULONG ulAddr = inet_addr("127.0.0.1");
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons((u_short)1234);
//4.绑定端口
/************************************************************************/
/* 为服务器端口定义的监听socket指定一个地址及端口(Port),这术客户端才知道在连接哪一个地址的哪个端口
/* 为此我们要调用bind()函数,该函数成功返回0,否则返回SOCKET_ERROR.
/************************************************************************/
if (SOCKET_ERROR == bind(sSocket,//Socket对象名
(SOCKADDR*)&service,//Socket 的地址值,即所在机器的IP地址
sizeof(service)))//name 的长度
{
closesocket(sSocket);
//关闭套件字
WSACleanup(); //释放所占资源
return false;
}
_beginthreadex(0, 0, RevcFromThreadProc, (LPVOID)sSocket, 0, 0);
getchar();
closesocket(sSocket); //关闭套接字
WSACleanup(); //释放套接字资源
return true;
//1.初始化OCKET
InitWinSock();
//2.建立Socket
//初始化winSock的动态链接库后 需要在服务器端建立一个监听socket,
//为此可以调用socket()函数来建立这个监听的socket,并定义通信协议
SOCKET sSocket;
sSocket = socket(AF_INET, //PF_INET(AF_INET)
SOCK_DGRAM, //Socket的类型 (SOCK_STREAM(TCP),SOCK_DGRAM(UDP))
IPPROTO_UDP);
//通信协议(如果使用者不指定则设为0)
if (INVALID_SOCKET == sSocket)
{
printf("创建套接字失败! 错误码:%d", WSAGetLastError());
WSACleanup(); //释放服务
return false;
}
//3.定义服务器地址
sockaddr_in service; //服务器套接字地址
service.sin_family = AF_INET;
ULONG ulAddr = inet_addr("127.0.0.1");
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons((u_short)1234);
//4.绑定端口
/************************************************************************/
/* 为服务器端口定义的监听socket指定一个地址及端口(Port),这术客户端才知道在连接哪一个地址的哪个端口
/* 为此我们要调用bind()函数,该函数成功返回0,否则返回SOCKET_ERROR.
/************************************************************************/
if (SOCKET_ERROR == bind(sSocket,//Socket对象名
(SOCKADDR*)&service,//Socket 的地址值,即所在机器的IP地址
sizeof(service)))//name 的长度
{
closesocket(sSocket);
//关闭套件字
WSACleanup(); //释放所占资源
return false;
}
_beginthreadex(0, 0, RevcFromThreadProc, (LPVOID)sSocket, 0, 0);
getchar();
closesocket(sSocket); //关闭套接字
WSACleanup(); //释放套接字资源
return true;
//初始化套接字
WSADATA stcData;
int nResult=0;
nResult=WSAStartup(MAKEWORD(2,2),&stcData);
if (nResult==SOCKET_ERROR)
{
return FALSE;
}
//创建套接字
SOCKET sock=socket(AF_INET,SOCK_STREAM,0);
//初始化地址
sockaddr_in addr={0};
addr.sin_family=AF_INET;
addr.sin_port=htons(1234);
addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
int nAddrLen=sizeof(sockaddr_in);//可以直接弄
//////////////////////////////
WSANETWORKEVENTS NetWorkEvent={0};//网络事件的记录和错误码
SOCKET sClientSocket=0;//当前发送事件的客户端的sock句柄
UINT uEventInfo=0;//事件对象的句柄数量
CLIENTINFO ClientInfo={0};//当前发送事件的客户端
EVENT_SOCKET_INFO EventSocketInfo={0};//保存事件和sock信息
//绑定
int nRet=0;
nRet=bind(sock,(sockaddr*)&addr,nAddrLen);
if (nRet==SOCKET_ERROR)
{
printf("绑定地址失败");
goto CloseSocket;
}
//监听
nRet=listen(sock,SOMAXCONN);
if (nRet)
{
printf("监听失败");
goto CloseSocket;
}
//创建一个事件对象
WSAEVENT wsaEvent=WSACreateEvent();
if (wsaEvent==WSA_INVALID_EVENT)
{
printf("创建事件对象失败");
goto CloseSocket;
}
//注册网络事件对象
if (WSAEventSelect(sock, //当前服务端的sock句柄
wsaEvent, //事件对象句柄
FD_ACCEPT|FD_CLOSE))//网络事件
{
printf("注册网络事件失败");
goto CloseSocket;
}
//保存事件对象和套接字
EventSocketInfo.EventArray[uEventInfo]=wsaEvent;
EventSocketInfo.SocketArray[uEventInfo++]=sock;//从1开始 uEventInfo初始值为0
while (true)
{
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
//等待网络事件发生
DWORD dwIndex=WSAWaitForMultipleEvents(uEventInfo, //事件句柄数量
EventSocketInfo.EventArray, //指向事件对象句柄的指针
FALSE, //等待事件句柄的全部数量
WSA_INFINITE, //调用该函数的阻塞时间
FALSE); //完成例程后不继续等待
if (WSA_WAIT_FAILED==dwIndex)
{
continue;
}
//手动设置无信号
WSAResetEvent(EventSocketInfo.EventArray);
//找到有信号对象的标号
//WSAWaitForMultipleEvents函数的返回值为 -WSA_WAIT_EVENT_0
dwIndex=dwIndex-WSA_WAIT_EVENT_0; //不减也可
if (WSAEnumNetworkEvents(EventSocketInfo.SocketArray[dwIndex],
EventSocketInfo.EventArray[dwIndex],
// EventSocketInfo.SocketArray[dwIndex],
&NetWorkEvent)
)
{
printf("调用“WSAEnumNetworkEvents”失败");
goto CloseSocket;
}
//响应 网络事件 连接
if ((NetWorkEvent.lNetworkEvents&FD_ACCEPT)&&(0==NetWorkEvent.iErrorCode[FD_ACCEPT_BIT]))
{
sClientSocket=accept(sock,(sockaddr*)&addr,&nAddrLen);
if (INVALID_SOCKET==sClientSocket)
{
printf("连接客户端失败");
continue;
}
//为新客户创建网络事件
EventSocketInfo.EventArray[uEventInfo]=WSACreateEvent();
//保存刚连接进来的客户端套接字
EventSocketInfo.SocketArray[uEventInfo]=sClientSocket;
//为该客户端注册网络事件
WSAEventSelect(sClientSocket,
EventSocketInfo.EventArray[uEventInfo],
FD_READ|FD_WRITE|FD_CLOSE);
uEventInfo++;
ClientInfo.ClientSock=sClientSocket;
g_ClientInfo.push_back(ClientInfo);
continue;
}
//接收消息
if ((NetWorkEvent.lNetworkEvents&FD_READ)&&
(0==NetWorkEvent.iErrorCode[FD_READ_BIT])
)
{
//此处可接受数据 可封装 传SOCKET 套接字及下标
char szBufTmp[1024]={0};
int iRecv=recv(EventSocketInfo.SocketArray[dwIndex],szBufTmp,sizeof(szBufTmp),0);
if (SOCKET_ERROR==iRecv||0==iRecv)
{
if (WSAEWOULDBLOCK==WSAGetLastError())
{
Sleep(20);
}
break;
}
else
{
if (szBufTmp[0] == '@')
{
for (int i = 0; i < g_ClientInfo.size(); i++)
{
if (EventSocketInfo.SocketArray[dwIndex] == g_ClientInfo[i].ClientSock)
{
strcpy_s(g_ClientInfo[i].ClientName, 19, szBufTmp + 1);
break;
}
}
}
else
{
int j;
for (j = 0; j < g_ClientInfo.size(); j++)
{
if (EventSocketInfo.SocketArray[dwIndex] == g_ClientInfo[j].ClientSock)
{
break;
}
}
for (int i = 0; i < g_ClientInfo.size(); i++)
{
char message[1044];
sprintf_s(message, "%s说:%s", g_ClientInfo[j].ClientName, szBufTmp);
if (i == j)
{
printf("%s\n", message);
continue;
}
int nSize = strlen(message) + 1;
int nErrCode = 0;
//发送数据
nErrCode = send(g_ClientInfo[i].ClientSock, //套接字
message, //发送数据缓冲区
nSize, //发送数据长度
0); //影响该函数的行为
if (SOCKET_ERROR == nErrCode)
{
::MessageBox(NULL, L"错误", L"发送数据失败", MB_OK);
}
}
}
//printf("%s",szBufTmp);
}
continue;
}
//关闭事件
if ((NetWorkEvent.lNetworkEvents&FD_CLOSE)&&
(0==NetWorkEvent.iErrorCode[FD_CLOSE_BIT])
)
{
//关闭socket套接字和释放事件对象的占有资源
closesocket(EventSocketInfo.SocketArray[dwIndex]);
WSACloseEvent(EventSocketInfo.EventArray[dwIndex]);
//将退出的事件客户端从事件数组中删除 并将之后的数据向前移动
//此步如果看过我上篇文章的源码 应该就很好理解了
for (int i=dwIndex;i<uEventInfo;i++)
{
EventSocketInfo.EventArray[dwIndex]=EventSocketInfo.EventArray[dwIndex+1];
EventSocketInfo.SocketArray[dwIndex]=EventSocketInfo.SocketArray[dwIndex+1];
}
uEventInfo--;
continue;
}
}
return TRUE;
CloseSocket:
closesocket(sock);
WSACleanup();
return FALSE;
- 指定需要的SOCKET最高版本
- 创建套接字
- 绑定IP及端口
- 监听
- 连接
- 接收数据
- 发送数据
- 关闭套接字
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)