c++简单网络编程基础(1)简单服务器

2023-12-14 13:55:22 浏览数 (1)

TCP/IP协议基础

首先要学习网络编程最基础的就是要理解TCP/IP协议,可以去网上找找类似文章理解一下。

接下来我们来进行简单的c 网络编程编码。

(1)Windows中进行c 网络编程前提

代码语言:c 复制
#include<WinSock2.h>//头文件
#pragm/a comment(lib , "ws2_32")//依赖库包含
// 1. 建立网络连接协议
WSADATA data;
if (WSAStartup(MAKEWORD(2, 2), &data) != 0) 
{
	std::cout << "Could not startup" << 'n';
}

(2)SOCKET(句柄 ,也叫套接字)

什么是句柄呢?教我的老哥是这样说的,网络中通信是需要地址的,句柄就相当于是你在小区哪一栋和你的门牌号,也就是ip和端口。接下来我们插入创造句柄的代码:

代码语言:c 复制
//2. 创造套接字
int server_sock = socket(AF_INET , SOCK_STREAM , 0);//AF_INET是TCP/IP--IPv4一般情况下管用
//,SOCK_STREAM是TCP流,0是默认适配句柄和协议族
if (server_sock == INVALID_SOCKET)
{
	std::cout << "error sock!" << "n";
	return 0;
}
std::cout << "1.  sock is ok !" << "n";

(3)bind(绑定ip和端口,将服务器的句柄确认)

bind(SOCKET sock , sockaddr* addr , int namelen);

第一个sock是本机服务器的句柄,第二个是存放ip和端口和协议族的结构体(可以先这样理解),第三个就是addr的字节大小,如果后续连接的客户端字节大小不一的话就会报错。

具体代码如下:

代码语言:c 复制
//3.绑定ip , 端口
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);//将主机字节顺序转换为网络字节顺序
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将点分十进制的IPv4地址转换成网络字节序列的长整型
int addr_len = sizeof(addr);
if (bind(server_sock, (sockaddr*)&addr, addr_len) == SOCKET_ERROR) {
	std::cout << "error bind!" << "n";
	return 0;
}
std::cout << "2.  bind is ok!" << "n";

(4)listen(监听句柄,相当于把自己的家的门打开让外人可以进来)

listen(SOCKET sock , int backlog)

第一个sock是本机服务器的句柄,第二个backlog是什么呢,backlog是挂起队列的最大长度,

具体理解是当你的服务器只能接收10个人,这时有30个人想进去你的服务器,剩下的20人你不可能不理人家把,这个就是系统创造的队列长度,将剩下20个人放进队列,后续一个一个连接,我们一般填写这个参数为SOMAXCONN让本机自己选择合适的个数。

具体代码如下:

代码语言:c 复制
//4.监听(打开大门)
if (listen(server_sock, SOMAXCONN) == SOCKET_ERROR) {
	std::cout << "error listen!" << "n";
	return 0;
}
std::cout << "3.  listen is ok!" << "n";

(5)accept接收客户端

accept(SOCKET sock ,sockaddr* addr ,int* addrlen);

第一个sock是服务端的sock,第二个addr是什么呢?这个addr是服务端为客户端连接分配的ip和端口,addrlen是分配的addr的字节大小;这个函数返回的值是一个SOCKET类型的值,也就是服务端为客户端连接而分配的句柄值。

我们今天只讲接收客户端连接,不讲接收客户端数据

具体代码如下:

代码语言:c 复制
//5接收客户端
while (true) {
	SOCKADDR_IN client_addr;
	int client_addr_len = sizeof(SOCKADDR_IN);
	int client_sock = accept(server_sock, (sockaddr*)&client_addr, &client_addr_len);
	
	if (SOCKET_ERROR == client_sock) {
		std::cout << "error accept" << "n";
		return 0;
	}
	std::cout << "sock[" << client_sock << "]  ip[" << inet_ntoa(client_addr.sin_addr) << "]  port[" << ntohs(client_addr.sin_port)
		<< "]n";
	std::thread t(Smallt , client_sock);//创造一个线程来对客户端进行数据的接收
	t.detach();
	
}

整段可运行代码如下:

代码语言:c 复制
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include<iostream>
#include<WinSock2.h>
#pragma comment(lib , "ws2_32")
#include<WS2tcpip.h>
#include<thread>


void Smallt(int csock) 
{	
	while (true) {
		char buff[1024] = { 0 };
		int recv_len = recv(csock, buff, 1024, 0);
		if (recv_len <= 0) {
			std::cout << "close socket" << "n";
			closesocket(csock);
			break;
		}
		
		std::cout << "recv >>>>> " << buff << "n";
		send(csock, buff, recv_len, 0);
	}
	return;
}

int main() 
{
	// 1. 建立网络连接协议
	WSADATA data;
	if (WSAStartup(MAKEWORD(2, 2), &data) != 0) 
	{
		std::cout << "Could not startup" << 'n';
	}

	//2. 创造套接字
	int server_sock = socket(AF_INET , SOCK_STREAM , 0);//AF_INET是TCP/IP--IPv4一般情况下管用,SOCK_STREAM是TCP流,0是默认适配句柄和协议族
	if (server_sock == INVALID_SOCKET)
	{
		std::cout << "error sock!" << "n";
		return 0;
	}
	std::cout << "1.  sock is ok !" << "n";

	//3.绑定ip , 端口
	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8080);//将主机字节顺序转换为网络字节顺序
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将点分十进制的IPv4地址转换成网络字节序列的长整型
	int addr_len = sizeof(addr);
	if (bind(server_sock, (sockaddr*)&addr, addr_len) == SOCKET_ERROR) {
		std::cout << "error bind!" << "n";
		return 0;
	}

	std::cout << "2.  bind is ok!" << "n";

	//4.监听(打开大门)
	if (listen(server_sock, SOMAXCONN) == SOCKET_ERROR) {
		std::cout << "error listen!" << "n";
		return 0;
	}
	std::cout << "3.  listen is ok!" << "n";

	//5接收客户端
	while (true) {
		SOCKADDR_IN client_addr;
		int client_addr_len = sizeof(SOCKADDR_IN);
		int client_sock = accept(server_sock, (sockaddr*)&client_addr, &client_addr_len);
		
		if (SOCKET_ERROR == client_sock) {
			std::cout << "error accept" << "n";
			return 0;
		}
		std::cout << "sock[" << client_sock << "]  ip[" << inet_ntoa(client_addr.sin_addr) << "]  port[" << ntohs(client_addr.sin_port)
			<< "]n";
		std::thread t(Smallt , client_sock);//创造一个线程来对客户端进行数据的接收
		t.detach();
		
	}


	closesocket(server_sock);//关闭服务端

	WSACleanup();//
	return 0;
}

0 人点赞