socket编程(C++/Windows)

目录

一、TCP通信流程

二、主要API分析

1.网络初始化

2.创建套接字(socket)

3.绑定端口(bind)

4.监听(listen)

5.客户端连接(connect)

6.接受连接(accept)

7.接收数据(recv)

8.发送数据(send)

9.关闭套接字(closesocket)

三、转换函数

1.htons函数(端口号)

2.inet_pton函数(IP地址)

四、服务端代码

五、客户端代码


  

一、TCP通信流程

330bf60ffd5e44e9998580d07ab425aa.png

    

二、主要API分析

1.网络初始化

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

  • wVersionRequested:用于指定Windows Sockets API的版本。
  • lpWSAData:指向WSADATA结构的指针,用于接收初始化的相关信息。

2.创建套接字(socket)

SOCKET socket(int af, int type, int protocol);

  • af:地址族,如AF_INET(IPv4)。
  • type:套接字类型,如SOCK_STREAM(流式套接字,用于TCP)。
  • protocol:协议类型,通常设为0表示使用默认协议。

3.绑定端口(bind)

int bind(SOCKET s, const struct sockaddr* name, int namelen);

  • s:要绑定的套接字。
  • name:指向包含地址和端口信息的sockaddr结构体的指针。
  • namelen:sockaddr结构体的长度。

4.监听(listen)

int listen(SOCKET s, int backlog);

  • s:要设置为监听状态的套接字。
  • backlog:等待连接队列的最大长度。

5.客户端连接(connect)

int connect(SOCKET s, const struct sockaddr* name, int namelen);

  • s:要连接的套接字。
  • name:指向包含服务端地址和端口信息的sockaddr结构指针。
  • namelen:sockaddr结构的长度。

6.接受连接(accept)

SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);

  • s:正在监听的套接字。
  • addr:指向sockaddr结构的指针,用于接收连接客户端的地址信息,可以为空。
  • addrlen:指向addr结构长度的指针,可以为空。

7.接收数据(recv)

int recv(SOCKET s, char* buf, int len, int flags);

  • s:接收数据的套接字。
  • buf:用于存储接收数据的缓冲区。
  • len:缓冲区的大小。
  • flags:标志位,通常设为0。

8.发送数据(send)

int send(SOCKET s, const char* buf, int len, int flags);

  • s:发送数据的套接字。
  • buf:要发送数据的缓冲区。
  • len:要发送数据的长度。
  • flags:标志位,通常设为0。

9.关闭套接字(closesocket)

int closesocket(SOCKET s);

  • s:要关闭的套接字。

  

三、转换函数

1.htons函数(端口号)

htons用于将主机字节序(Host Byte Order)转换为网络字节序(Network Byte Order)。

在网络通信中,不同的系统可能使用不同的字节顺序来表示数值,为了确保在网络中正确地传输数据,需要将数据转换为网络字节序,即将小端序转换为大端序。

u_short htons(u_short hostshort);

  • hostshort:一个16位的无符号整数,表示主机字节序的值。

2.inet_pton函数(IP地址)

int inet_pton(int af, const char *src, void *dst);

inet_pton用于将字符串形式的 IP 地址转换为网络字节序的二进制形式。

  • af:地址族(AF_INET-IPv4,AF_INET6-IPv6)。
  • src:IP地址字符串。
  • dst:用于存储转换结果。

  

四、服务端代码

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

using namespace std;

int main(void)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_socket == INVALID_SOCKET) {
		cerr << "error" << endl;
		return -1;
	}

	struct sockaddr_in local = { 0 };
	local.sin_family = AF_INET;
	local.sin_addr.s_addr = INADDR_ANY;
	local.sin_port = htons(9999);
	
	if (bind(listen_socket, (struct sockaddr*)&local, sizeof local) == INVALID_SOCKET) {
		cerr << "error" << endl;
		return -1;
	}

	if (listen(listen_socket, 128) == -1) {
		cerr << "error" << endl;
		return -1;
	}

	while (true){
		SOCKET client_socket = accept(listen_socket, nullptr, nullptr);
		if (client_socket == INVALID_SOCKET) {
			continue;
		}
        cout << "client connect: " << client_socket << endl;		

		thread th([](SOCKET client_socket){
			while (true) {
				char buffer[1024] = { 0 };
				int ret = recv(client_socket, buffer, sizeof buffer, 0);
				if (ret <= 0) {
					cout << "client disconnect: " << client_socket << endl;
					break;
				}
				cout << buffer << endl;
				send(client_socket, buffer, strlen(buffer), 0);
			}
			closesocket(client_socket);
		}, client_socket);

		th.detach();
	}

	return 0;
}

  

五、客户端代码

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

using namespace std;

int main(void)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (client_socket == INVALID_SOCKET) {
		cerr << "error" << endl;
		return -1;
	}

	struct sockaddr_in target;
	target.sin_family = AF_INET;
	target.sin_port = htons(9999);
	inet_pton(AF_INET, "127.0.0.1", &target.sin_addr.s_addr);
    //target.sin_addr.s_addr = inet_addr("127.0.0.1");

	if (connect(client_socket, (struct sockaddr*)&target, sizeof target) == INVALID_SOCKET) {
		cerr << "error" << endl;
		closesocket(client_socket);
		return -1;
	}

	while (true) {
		char buffer1[1024] = { 0 };
		cout << "enter: ";
		cin >> buffer1;
		send(client_socket, buffer1, strlen(buffer1), 0);

		char buffer2[1024] = { 0 };
		int ret = recv(client_socket, buffer2, sizeof buffer2, 0);
		if (ret <= 0) {
			cout << "server disconnect." << endl;
		}
		cout << buffer2 << endl;

	}
	closesocket(client_socket);

	return 0;
}

    

 相关文章推荐:

Socket 编程基础

面试官,不要再问我三次握手和四次挥手

TCP的三次握手与四次挥手

参考视频:

https://www.bilibili.com/video/BV1aW4y1w7Ui/?spm_id_from=333.337.search-card.all.click

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值