[整理自用] c++百万级别高并发网络通信(一)

文章目录

  • 基础API
    • 简易TCP客户端与服务端
    • 基础模型搭建
    • 简易TCP服务器代码
      • 详细解读:创建套接字
      • 详细解读:绑定bind
      • 详细解读:监听listen
      • 详细解读:ACCEPT
      • 详细解读:send
    • 简易TCP客户端代码

视频学习地址

基础API

简易TCP客户端与服务端

通过IP地址和端口找到服务器
网络传输
网络传输
建立一个套接字soket
连接服务器connect
向服务器发送数据send
监听网络端口listen,启动监听模式
接受服务端数据recv,和上一步之间可能存在着多次循环
接受客户端数据recv,阻塞直到有数据可读
关闭soket
建立一个socket,申请一个端口用于socket服务
绑定端口bind
等待客户端链接accept,阻塞直到客户端连接
向客户端发送数据send,和上一步之间可能存在着多次循环
关闭socket

基础模型搭建

1. 头文件包含:(Windows)

ws2_32.lib的静态链接库,不然创建socket的时候回找不到对应的函数。

#include
#include
  • 两个文件顺序最好是不要调换,因为windows.h是socket第一代接口,如果相符可能会导致宏重复定义
  • 在开始定义一个宏WIN32_LEAN_AND_MEAN(微软官方解决方案),及时文件顺序有误也没有关系:
#define WIN32_LEAN_AND_MEAN
#include
#include

启动和关闭

int main()
{
    WORD ver = MAKEWORD(2,2);//调用API2代创建2.x版本
    WSADATA dat;
    WSAStartup(ver,&dat);//启动
    WSAcleanup();//关闭
}

简易TCP服务器代码

功能:建立简易的TCP服务器,监听各个客户端,只要有客户端加入就发送msgbuf里面的东西。

#define WIN32_LEAN_AND_MEAN
#define SOCKET int  //VS2015已经定义好的,可以直接用
#include
#include
#include
int main()
{
  WORD ver = MAKEWORD(2,2);//调用API2代创建2.x版本
  WSADATA dat;
  WSAStartup(ver,&dat);//启动
  //创建套接字
  SOCKET  seradd =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  //bind
  SOCKADDR_IN _sin = {};	
  _sin .sin_family = AF_INET;
//sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序。所以需要转换host to net unsigned.数字可改 
  _sin .sin_port = htons(1234);
  _sin.sin_addr_s_un.S_addr = INADDR_ANY;//访问本机任何网络地址都可以,具体也可以改为本机的某个特定地址
  if (SOCKET_ERROR == bind(seradd , (sockaddr *) &_sin , sizeof(_sin)))
  {
  	std::cout<<"绑定失败"<<endl;
  }
  //监听
  if (SOCKET_ERROR == listen(seradd,5))
  {
  	std::cout<<"绑定失败"<<endl;
  }
  //接受
  sockaddr_in clentAddr = {};//不用赋值了,因为是监听到的,不是给定的
  int nAddrLen = sizeof(sockaddr_in);//给定长度
  SOCKET _cSock = INVAID_SOCKET;
  //发送内容需要预先说定
  char msgbuf[] = "XXXXXXX";
  while(true)
  {
  	_cSock = accept(seradd,(sockaddr *) &clentAddr,nAddrLen);
  	if(_cSock = INVAID_SOCKET)
  	{
  		std::cout<<"获取失败"<<endl;
  	}
  	send(_cSock,msgbuf,sizeof(msgbuf)+1,0);//发送msgbuf中的内容。如果长度确定则不应该每次都重新计算
  }
  closesocket(seradd);
  WSAcleanup();//关闭
}

详细解读:创建套接字

int socket(
		   int family, //协议簇:AF_INET,AF_INET6,AF_LOCAL,AF_ROUTE,AF_KEY,分别是IPv4,IPv6协议,UNIX域协议,路由套接口,密钥套接口
           int type,//type指定套接口类型
           int protocol
           ); 
协议簇 实际名字
AF_INET IPv4 (一般是这个
AF_INET6 IPv6协议
AF_LOCAL UNIX域协议
AF_ROUTE 路由套接口
AF_KEY 密钥套接口
套接口类型 实际名字
SOCK_STREAM 流套接字(一般是这个
SOCK_DGRAM 数据报套接字
SOCK_SEQPACKET 有序分组套接字(不常用了
SOCK_RAW 原始套接字
protocol 实际名字
IPPROTO_TCP TCP协议(一般是这个
IPPROTO_UDP UDP协议

详细解读:绑定bind

 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd: 就是之前socket创建时做出来的标识符或者叫做套接字。
sockaddrLINUX下需要包括头文件#include 中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了。
所以需要使用sockaddr_in!!
sockaddr_in在头文件#include#include 中定义:
在这里插入图片描述
赋值:

sockaddr_in _sin = {};
_sin .sin_family = AF_INET;
//sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序。所以需要转换host to net unsigned.数字可改 
_sin .sin_port = htons(1234);
_sin.sin_addr_s_un.S_addr = INADDR_ANY;//访问本机任何网络地址都可以,具体也可以改为本机的某个特定地址
if (SOCKET_ERROR == bind(seradd , (sockaddr *) &_sin , sizeof(_sin)))
{
	std::cout<<"绑定失败"<<endl;
}

详细解读:监听listen

    int listen(int sockfd, int backlog);

backlog表示最大连接数,根据需求确定。

详细解读:ACCEPT

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

sockaddr_in clentAddr = {};//不用赋值了,因为是监听到的,不是给定的
int nAddrLen = sizeof(sockaddr_in);//给定长度
SOCKET _cSock = INVAID_SOCKET;
_cSock = accept(seradd,(sockaddr *) &clentAddr,nAddrLen);
if(_cSock = INVAID_SOCKET)
{
	std::cout<<"获取失败"<<endl;
}

详细解读:send

send(_cSock,msgbuf,sizeof(msgbuf)+1,0);//发送msgbuf中的内容。

功能:在已建立连接的套接字上发送数据.
格式:int send(SOCKET s, const char *buf, int len, int flags)。
参数:s-已建立连接的套接字;buf-存放将要发送的数据的缓冲区指针;len-发送缓冲区中的字符数;
flags-控制数据传输方式:
(1)0:接收的是正常数据,无特殊行为。
(2)MSG_DONTROUTE:表示目标主机就在本地网络中,无需路由选择。
(3)MSG_OOB:表示处理带外数据。
返回值:发送成功时返回发送的数据长度,连接结束时返回0,连接失败时返回SOCKET_ERROR。

简易TCP客户端代码

#define WIN32_LEAN_AND_MEAN
#include
#include
int main()
{
    WORD ver = MAKEWORD(2,2);//调用API2代创建2.x版本
    WSADATA dat;
    WSAStartup(ver,&dat);//启动
    SOCKET  cliadd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    //bind
    SOCKADDR_IN _sin = {};	
    _sin .sin_family = AF_INET;
//sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序。所以需要转换host to net unsigned.数字可改 
	_sin .sin_port = htons(4567);//和拂去其不同
	_sin.sin_addr_s_un.S_addr = inet_addr("127.0.0.1");//绑定服务器地址
	if (SOCKET_ERROR == connect(cliadd, (sockaddr *) &_sin , sizeof(_sin)))
	{
		std::cout<<"连接失败"<<endl;
	}
	//接受数据
	char recvBuf[256] = {};//最多可以接受的字符
	int nLen = recv(cliadd,recvBuf,0);
	if(nLen > 0 )
	{
		cout<<"接受到的数据:"<<recvBuf<<endl;
	}
	closesocket(cliadd);
    WSAcleanup();//关闭
}

你可能感兴趣的:(网络编程,项目)