1.Socket头文件的包含及库的链接:
#include
#pragma comment(lib, "ws2_32.lib")
2.初始化和卸载
- WSAStartup
int WSAStartup(
__inWORD wVersionRequested,
__outLPWSADATA lpWSAData
);
wVersionRequested
调用程序使用windows socket的最高版本。 高字节指定小的版本号,低字节指定高的版本号。
lpWSAData
指向WSADATA数据结构体指针,接收Windows Socket的实现细节。
返回值
如果成功,WSAStartup函数返回0。否则,返回下面列表显示的错误码之一。
WSAStartup函数直接在返回值中返回扩展的错误码,不再需要调用WSAGetLastError函数。
错误码 | 解释 |
WSASYSNOTREADY | 网络通信中下层的网络子系统没准备好 |
WSAVERNOTSUPPORTED | Socket实现提供版本和socket需要的版本不符 |
WSAEINPROGRESS | 一个阻塞的Socket操作正在进行 |
WSAEPROCLIM | Socket的实现超过Socket支持的任务数限制 |
WSAEFAULT | lpWSAData参数不是一个合法的指针 |
- MAKEWORD
WORD MAKEWORD(
BYTE bLow, //指定新变量的低字节序;
BYTE bHigh //指定新变量的高字节序;
);
MAKEWORD 宏 平台:SDK这个宏创建一个无符号16位整型,通过连接两个给定的无符号参数。(注:typedef unsigned short WORD; )
宏的原始定义:
#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
返回值:一个无符号16位整形数。
- 初始化:
BOOL WinSockInit()
{
WSADATA wsaData = https://www.it610.com/article/{0};
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR) {
return TRUE;
}else{
return FALSE;
}
}
- 卸载:
void WinSockUnLoad()
{
WSACleanup();
}
3.Socket函数:
- socket
SOCKET WSAAPI socket(
_In_int af, //地址描述
_In_int type, //套接字类型
_In_int protocol //协议类型
);
domain:协议族,
常用的有AF_INET、AF_INET6、AF_LOCAL、AF_ROUTE其中AF_INET代表使用ipv4地址
AF_INET,指定so_pcb中的地址要采用ipv4地址类型
AF_INET6,指定so_pcb中的地址要采用ipv6的地址类型
AF_LOCAL/AF_UNIX,指定so_pcb中的地址要使用绝对路径名
type:
socket类型,常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等
SOCK_STREAM是基于TCP的,数据传输比较有保障。SOCK_DGRAM是基于UDP的,专门用于局域网,基于广播SOCK_STREAM 是数据流,一般是tcp/ip协议的编程,SOCK_DGRAM分是数据抱,是udp协议网络编程
protocol:协议。
常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等
IPPROTO_TCP,TCP协议
IPPROTO_UDP,UPD协议
0,如果指定为0,表示由内核根据so_type指定默认的通信协议
文章图片
成功时,返回非负数的socket描述符;失败是返回-1。socket描述符是一个指向内部数据结构的指针
【网络编程--- 通用Socket函数[2]】使用:
//创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
cout << "serverSocket = socket(AF_INET, SOCK_STREAM, 0) execute failed!" << endl;
return -1;
}
- bind
int bind(
_In_SOCKET s, //套接字句柄
_In_const struct sockaddr *name, //要关联的本地地址
_In_int namelen //地址的长度
);
使用:
//初始化服务器地址族变量
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//端口号
//绑定
iRet = bind(serverSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (iRet == SOCKET_ERROR)
{
cout << "bind(serverSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) execute failed!" << endl;
return -1;
}
- listen
int listen(
_In_SOCKET s, //套接字句柄
_In_int backlog //监听队列中允许保持的尚未处理的最大连接数量
);
使用:
//监听
iRet = listen(serverSocket, CONNECT_NUM_MAX);
if (iRet == SOCKET_ERROR)
{
cout << "listen(serverSocket, 10) execute failed!" << endl;
return -1;
}
- accept
SOCKET accept(
_In_SOCKET s, //套接字句柄
_Out_struct sockaddr *addr, //一个指向 sockaddr_in 结构的指针,用于取得对方的地址信息
_Inout_int *addrlen //一个指向地址长度的指针
);
使用:
//等待连接_接收_发送
SOCKADDR_IN clientAddr;
int len = sizeof(SOCKADDR);
SOCKET connSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &len);
if (connSocket == INVALID_SOCKET)
{
cout << "accept(serverSocket, (SOCKADDR*)&clientAddr, &len) execute failed!" << endl;
return -1;
}
4.简单的例子
- 服务器端代码:
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define CONNECT_NUM_MAX 10
using namespace std;
int main()
{
//加载套接字库
WSADATA wsaData;
int iRet = 0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
cout << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed!" << endl;
;
return -1;
}
if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
{
WSACleanup();
cout << "WSADATA version is not correct!" << endl;
return -1;
}
//创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
cout << "serverSocket = socket(AF_INET, SOCK_STREAM, 0) execute failed!" << endl;
return -1;
}
//初始化服务器地址族变量
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//绑定
iRet = bind(serverSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (iRet == SOCKET_ERROR)
{
cout << "bind(serverSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) execute failed!" << endl;
return -1;
}
//监听
iRet = listen(serverSocket, CONNECT_NUM_MAX);
if (iRet == SOCKET_ERROR)
{
cout << "listen(serverSocket, 10) execute failed!" << endl;
return -1;
}
//等待连接_接收_发送
SOCKADDR_IN clientAddr;
int len = sizeof(SOCKADDR);
while (1)
{
SOCKET connSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &len);
if (connSocket == INVALID_SOCKET)
{
cout << "accept(serverSocket, (SOCKADDR*)&clientAddr, &len) execute failed!" << endl;
return -1;
}
char sendBuf[100];
sprintf_s(sendBuf, "Welcome %s", inet_ntoa(clientAddr.sin_addr));
send(connSocket, sendBuf, strlen(sendBuf)+1, 0);
char recvBuf[100];
recv(connSocket, recvBuf, 100, 0);
printf("%s\n", recvBuf);
closesocket(connSocket);
}system("pause");
return 0;
}
- 客户端代码:
#include
#include
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main()
{
//加载套接字库
WSADATA wsaData;
int iRet =0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
cout << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed!" << endl;
return -1;
}
if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
{
WSACleanup();
cout << "WSADATA version is not correct!" << endl;
return -1;
}
//创建套接字
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET)
{
cout << "clientSocket = socket(AF_INET, SOCK_STREAM, 0) execute failed!" << endl;
return -1;
}
//初始化服务器端地址族变量
SOCKADDR_IN srvAddr;
srvAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
srvAddr.sin_family = AF_INET;
srvAddr.sin_port = htons(6000);
//连接服务器
iRet = connect(clientSocket, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR));
if (0 != iRet)
{
cout << "connect(clientSocket, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR)) execute failed!" << endl;
return -1;
}
//接收消息
char recvBuf[100];
recv(clientSocket, recvBuf, 100, 0);
printf("%s\n", recvBuf);
//发送消息
char sendBuf[100];
sprintf_s(sendBuf, "Hello, This is client %s", "兔子");
send(clientSocket, sendBuf, strlen(sendBuf)+1, 0);
//清理
closesocket(clientSocket);
WSACleanup();
system("pause");
return 0;
}
- 程序运行截图:
文章图片
推荐阅读
- 日记博文|几种网络编程方式的比较
- C++|浅析boost::asio::deadline_timer运行机制
- JQuery Easy UI 使用
- nginx 源码(5)事件驱动架构
- nginx 源码(2)运行
- 网络编程|nginx 源码(4)主流程
- nginx 源码(1)编译
- 网络编程|nginx 源码(3)调试
- epoll如何判断客户端不可读
- 关于TCP协议收到数据不完整