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;
}