头文件:
#include <stdio.h>
#include <WS2tcpip.h>
#include <string>
#pragma comment(lib, "WS2_32")
using namespace std;
int OnConnect_server(int port);
int OnConnect_client(string ip, int port);
服务器:
int OnConnect_server(int port)
{
SOCKET Socket_Server;
SOCKET Socket_client;
WSADATA wsaData;
WORD wVersionRet; //调用版本返回值
sockaddr_in serAddr; //服务端地址
memset(&serAddr, 0, sizeof(serAddr));
int nNetTimeout;
//初始化winsock库
wVersionRet = MAKEWORD(2, 2);
if (WSAStartup(wVersionRet, &wsaData) != 0)//加载套接字库 以及确认socket版本
{
// 初始化winsock服务失败,socket错误
return -1;
}
// 检测是否支持2.2版本的socket
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
// socket错误
//AfxMessageBox(_T("不支持2.2版本的socket"));
return -1;
}
serAddr.sin_family = AF_INET; //填写要连接的服务器地址信息
serAddr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr()将命令行中输入的点分IP地址转换为二进制表示的网络字节序IP地址
serAddr.sin_port = htons(port);
//服务器套接字
Socket_Server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW)。基于TCP的socket编程是采用的流式套接字。
//protocol:协议类型,通常是IPPROTO_TCP或IPPROTO_UDP
if (INVALID_SOCKET == Socket_Server)
{
//释放winsock库
WSACleanup();
Socket_Server = 0;
return -1;
}
bind(Socket_Server, (struct sockaddr*)&serAddr, sizeof(serAddr)); //与服务器端建立连接
listen(Socket_Server, 1); //将套接字置入监听模式并准备接受连接请求,请求1是连接队列的最大长度
// 接收到客户端连接,分配一个客户端套接字
SOCKADDR_IN addr_client; //存储client地址信息
int len = sizeof(SOCKADDR);
Socket_client = accept(Socket_Server, (SOCKADDR*)&addr_client, &len);
if (SOCKET_ERROR != Socket_client)
{
return Socket_client;
}
return -1;
}
客户端:
int OnConnect_client(string ip, int port)
{
SOCKET Socket_client;
WSADATA wsaData;
WORD wVersionRet; //调用版本返回值
sockaddr_in serAddr; //服务端地址
memset(&serAddr, 0, sizeof(serAddr));
int nNetTimeout;
//初始化winsock库
wVersionRet = MAKEWORD(2, 2);
if (WSAStartup(wVersionRet, &wsaData) != 0)//加载套接字库 以及确认socket版本
{
// 初始化winsock服务失败,socket错误
return -1;
}
// 检测是否支持2.2版本的socket
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
// socket错误
//AfxMessageBox(_T("不支持2.2版本的socket"));
return -1;
}
//创建客户端套接字
Socket_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW)。基于TCP的socket编程是采用的流式套接字。
//protocol:协议类型,通常是IPPROTO_TCP或IPPROTO_UDP
if (INVALID_SOCKET == Socket_client)
{
//释放winsock库
WSACleanup();
return -1;
}
//设置非阻塞方式连接
unsigned long ul = 1;
int ret = ioctlsocket(Socket_client, FIONBIO, (unsigned long*)&ul);
if (ret == SOCKET_ERROR)
{
return -1;
}
nNetTimeout = 1000;
if (SOCKET_ERROR == setsockopt(Socket_client, SOL_SOCKET, SO_SNDTIMEO, (char*)&nNetTimeout, sizeof(int)))
{
//AfxMessageBox(_T("设置发送超时时间失败"));
return -1;
}
//接收时限
if (SOCKET_ERROR == setsockopt(Socket_client, SOL_SOCKET, SO_RCVTIMEO, (char*)&nNetTimeout, sizeof(int)))
{
//AfxMessageBox(_T("设置接收超时时间失败"));
return -1;
}
serAddr.sin_family = PF_INET; //声明地址格式是TCP/IP格式
serAddr.sin_port = htons(port); //指明连接服务器的端口号,htons可用于主机序与网络序之间的转化
inet_pton(AF_INET, ip.c_str(), (void*)&serAddr.sin_addr.S_un.S_addr);//指明连接服务器的IP地址,sin_addr字段也是一个结构体
//连接指明的服务器上
int retrytime = 0;
while (retrytime <= 3)
{
connect(Socket_client, (struct sockaddr*)&serAddr, sizeof(SOCKADDR_IN));//连接后可以用sClient来使用这个连接
//select 模型,即设置超时
fd_set r;
FD_ZERO(&r);
FD_SET(Socket_client, &r);
struct timeval timeout;
timeout.tv_sec = nNetTimeout / 1000; //连接超时
timeout.tv_usec = nNetTimeout % 1000;
ret = select(0, 0, &r, 0, &timeout);
if (ret <= 0)
{
retrytime++;
}
else
{
//设置堵塞型
ul = 0;
ioctlsocket(Socket_client, FIONBIO, (unsigned long*)&ul);
//WSAAsyncSelect(aSocket, GetSafeHwnd(), WM_Socket,FD_CLOSE);
return Socket_client;
}
}
// 关闭连接
closesocket(Socket_client);
// 释放winsock
WSACleanup();
return -1;
}
调用:
int main()
{
string ip = "127.0.0.1";
int port = 9877;
int socketmode;
int SockNo;
socketmode = 1;
if (socketmode == 1)
{
SockNo=OnConnect_server(port);
}
else
{
SockNo = OnConnect_client(ip, port);
}
if (SockNo>0)
{
//发送
string sendData;
sendData = "123";
int nsend = send(SockNo, sendData.c_str(), strlen(sendData.c_str()), 0);
if (nsend <= 0)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
return -2;
}
else if (WSAECONNRESET == WSAGetLastError())
{
return -1;
}
else
{
return -3;
}
}
//接收
char szText[12288];
ZeroMemory(szText, sizeof(szText));
int nrecv = recv(SockNo, szText, 12288, 0);
if (nrecv <= 0)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
return -2;
}
else if (WSAECONNRESET == WSAGetLastError())
{
return -1;
}
else
{
return -3;
}
}
printf("%s", szText);
}
}