本文已参与「新人创作礼」活动,一起开启掘金创作之路。
基础网络函数介绍(C++)
头文件 winsock2.h 库文件 ws2_32.lib
创建套接字
SOCKET socket(协议族类型,协议类型,协议); 协议族: AF_INET(IPV4协议) AF_INET6(IPV6协议) 协议类型:SOCK_STREAM(流式协议TCP) SOCK_DGRAM(报文协议 UDP) 协议:可以填写0自适应协议
也可以根据协议类型填写[SOCK_STREAM对应IPPROTO_TCP] [SOCK_DGRAM 对应IPPROTO_UDP] 返回值: 成功返回SOCKET句柄,失败返回INVALID_SOCKET
SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == sock)
printf("创建socket失败\n");
sockaddr_in 结构体
struct in_addr{
in_addr_t s_addr; //32位的IP地址
};
struct sockaddr_in{
sa_family_t sin_family; //地址族(Address Family),也就是地址类型
uint16_t sin_port; //16位的端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用,一般用0填充 字节对齐
};
//创建sockaddr_in结构体变量
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); //每个字节都用0填充
addr.sin_family = AF_INET; //使用IPv4地址
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
addr.sin_port = htons(7890); //端口
bind函数
将 SOCKET语句和创建的 sockaddr_in结构体进行关联 在本地打开一个端口 int bind(SOCKET sock, const struct sockaddr* addr , int len); sock:创建的SOCKET句柄 addr:定义的struct sockaddr_in结构体 len:struct sockaddr_in的长度 返回值:0表示成功 -1表示失败
int nRet = bind(sock,(struct sockaddr*)&addr,sizeof(addr));
if(0!=nRet)
printf("bind Error\n");
listen函数
// 让SOCKET进入监听状态
// int listen(SOCKET sock, int backlog);
// sock:
Cpp实例
使用socket创建C++服务端。
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
//网络库文件
#include <winsock2.h>
//引入ws2_32.lib
#pragma comment(lib,"ws2_32.lib")
int main()
{
//在window下面需要额外的加载socket库
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("create WSAStartip Error %d\n", GetLastError());
return 0;
}
//1.创建一个socket
//socket(协议类型IP V4 IPV6,传输类型TCP UDP,0 可选择TCP或其它,0表示自动根据前面两个参数进行自动选择)
//tcp叫做流式协议
//SOCK_STRAM ==> TCP
//SOCK_DGRAM ==> UDP
SOCKET serverSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//0 or IPPROTO_TCP
if (INVALID_SOCKET == serverSock)
{
printf("create socket Error %d\n", GetLastError());
return 0;
}
//2.IP端口和SOCKET关联
//bind 会通过头两个字节,判断真实的数据结构大小,然后比较携带的头和头后面的数据是否一样
//失败返回INVALID_SOCKET,bind(句柄,IP端口地址结构体,第二个形参的字节大小);
//SOCKADDR;//16字节
SOCKADDR_IN serverAddr;//16字节
serverAddr.sin_family = AF_INET;//协议族类型,IPV4协议族
//host to network short
//必须是网络字节序,网络字节序转化为主机字节序时,一定要注意是否需要转换。网络字节序采用大端(big-endian)排序方式。
//字节序是指大于一个字节类型的数据在内存中的存放顺序。是在跨平台和网络编程中时常要考虑的问题
//大端:高位字节排放在内存中的低地址端,低位字节排放在内存中的高地址端。
//小端:低位字节排放在内存中的低地址端,高位字节排放在内存中的高地址端。
//00 ff(255) 大端
//ff 00 小端
serverAddr.sin_port = htons(7890);
//127.0.0.1 localhost 永远指向本机
//0.0.0.0 绑定所有的端口
//inet_addr将点分十进制的字符串转化为网络地址
serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//点分十进制
if (INVALID_SOCKET == bind(serverSock, (sockaddr *)&serverAddr, sizeof(SOCKADDR_IN)))
{
printf("bin Error %d\n", GetLastError());
return 0;
}
printf("bind ok\n");
//3.监听端口
//允许最大排队数量
//listen(监听句柄, 监听队列数量);
if (INVALID_SOCKET == listen(serverSock, 5))
{
printf("listen Error %d\n", GetLastError());
return 0;
}
printf("listen ok\n");
while (true)
{
printf("Hold User\n");
//4.等待用户连接
//accept(服务端句柄, 客户端IP和端口, 第二个参数的大小);
SOCKET clientSocket;
SOCKADDR_IN clientAddr;
int clientAddrLen = sizeof(SOCKADDR_IN);
clientSocket = accept(serverSock, (sockaddr *)&clientAddr, &clientAddrLen);
if (INVALID_SOCKET == clientSocket)
{
printf("accept Error %d\n", GetLastError());
return 0;
}
printf("accpet Ok SOCKET[%d] ip[%s] port[%d]\n",
clientSocket, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
//5.向连接的客户端发送数据
//发送的数据长度 = send(句柄, 数据, 数据长度, 0);
char buffer[1024] = "hello world";
printf("length:%d\n", send(clientSocket, buffer, strlen(buffer) + 1, 0));
//关闭客户端
closesocket(clientSocket);
}
//关闭服务端
closesocket(serverSock);
return 0;
}
版权声明:本文为CSDN博主「ufgnix0802」的原创文章:
原文链接:(blog.csdn.net/qq135595696…)