c++实现TCPUDP

embedded/2024/10/21 5:50:59/

网络通信作业之前的学习  !(>。<)!

一.TCP

1.服务端流程

        1.创建socket套接字

                socket套接字可以理解成网络接口,只有通过了socket套接字才能跟对应的电脑进行通信

        2.给这个socket绑定一个端口号

                IP地址是指定电脑的 端口号是指定电脑上面某个软件的

        3.给socket开启监听属性

                这个socket只能用来接收连接 不能用来做通讯

        4.等待客户端连接

        5.开始通讯

        6.关闭连接

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{//windows上使用网络功能需要开始网络权限WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);//1.创建socket套接字/*socket(int af,  //协议地址簇 ipv4/ipv6 对应 AF_INET/AF_INET6int type,	//类型	流式协议/帧式协议 对应 SOCK_STREAM/SOCK_DGRAMint protocol	//保护协议 tcp/udp不用填保护协议 直接填0);*///此处是服务端socket,所以我们一般起名叫监听socketSOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);//SOCKET是一个无符号的长整型,就是一个整数,可以直接打印出来//未开启网络结果为-1 即无效的socket -> INVALID_SOCKETif (INVALID_SOCKET == listen_socket){printf("create listen socket failed !!! errocode: %d\n", GetLastError());return -1;}//2.给这个socket绑定一个端口号//struct sockaddr_in {//	ADDRESS_FAMILY sin_family;	//协议地址簇//	USHORT sin_port;	//端口号//	IN_ADDR sin_addr;	//IP地址//	CHAR sin_zero[8];	//保留字节 -> 协议升级会用//};//大小端问题://	一个数字在计算机中存储以二进制存储,对端口来讲占两个字节//	编程中最小单位我们通常用字节来算,很少用位算//	存数据的时候会有先后的问题 8080 -> 1F90(大端序号,高位放前面【千百个十】)//	但是本地电脑的存储方式是以小端序存储的【个十百千】//unsigned short a = 8080;//unsigned short* p = &a;struct sockaddr_in local = { 0 };local.sin_family = AF_INET;local.sin_port = htons(8080);	//大小端问题 中间设备使用的是大端序//服务端 选项 网卡 127.0.0.1(本地环回)只接受哪个网卡的数据//一般写0.0.0.0 不管哪个数据库来 只要有我都接受//INADDR_ANY整数 占4个字节//local.sin_addr.s_addr = htonl(INADDR_ANY);//手动指定local.sin_addr.s_addr = inet_addr("0.0.0.0"); //字符串IP转换成整数IP//绑定 给上面定义的socket绑定我们指定的内容/*int bind(SOCKET s,	//对哪个socket进行绑定const struct sockaddr FAR * name,	//sockaddr的结构int namelen	//长度);  返回整数类型*///为什么使用sockaddr结构而不是sockaddr_in结构?(两个结构体的大小一模一样)/*struct sockaddr {ADDRESS_FAMILY sa_family;CHAR sa_data[14];}   用这个方便扩展  通用的结构*/ if (-1 == bind(listen_socket, (struct sockaddr*)&local, sizeof(local))) {printf("bind socket failed !!! errocode: %d\n", GetLastError());return -1;}//3.给socket开启监听属性/*int listen(SOCKET s,int backlog	//半连接队列长度);*/if (-1 == listen(listen_socket, 10)) {printf("start listen socket failed !!! errocode: %d\n", GetLastError());return -1;}//以上准备工作结束//4.等待客户端连接//返回的客户端socket才是跟客户端可以通讯的一个socket//listen_socket唯一的作用就是等待连接 最后返回一个socket出来//accept()是阻塞函数,等到有客户端连接进来就接受连接,然后染回,否则就阻塞/*SOCKET accept(SOCKET s,	//监听socketstruct sockaddr * addr,	//客户端的IP地址和端口号int * addrlen	//结构的大小  为什么是指针 因为可填可不填 要填就要和上面的addr都填);*///如果要跟多个客户端通讯 需要有while循环while (1) {SOCKET client_socket = accept(listen_socket, NULL, NULL);if (INVALID_SOCKET == client_socket)continue;//5.开始通讯(B/S) //通过浏览器访问一个网站的时候 //浏览器会发送一个http请求 http是tcp的上层协议 所以写tcp是可以接收http的报文的//接收发送的报文char buffer[1024] = { 0 };/*int recv(SOCKET s,	//客户端socketchar* buf,	//接受的数据存到哪里int len,	//接受的长度int flags	//0);*/recv(client_socket, buffer, 1024, 0);printf("%s\n", buffer);//6.关闭连接closesocket(client_socket);}return 0;
}

错误码查找

大小端问题

中间设备使用的是大端序(路由器) 要从主机转换成中间件能使用的 -> htons()

不安全问题:把安全开发关掉

程序一旦弹出

代表监听已经开启了

模拟时输入127.0.0.1:8080  可以收到数据 --> tcp连接没问题

2.客户端流程

        1.创建socket套接字(通过套接字连接到服务端)

        2.连接服务器

        3.开始通讯

        4.关闭连接

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);//1.创建socket套接字(通过套接字连接到服务端)SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == client_socket) {print("create socket failed!!!\n");return -1;}//2.连接服务器struct sockaddr_in target;target.sin_family = AF_INET;target.sin_port = htons(8080);target.sin_addr.s_addr = inet_addr("127.0.0.1");if (-1 == connect(client_socket, (struct sockaddr*)&target, sizeof(target))){printf("connet server failed !!!\n");closesocket(client_socket);return -1;}//3.开始通讯 send recv//回显服务器 -> 发送什么会回复什么while (1){char sbuffer[1024] = { 0 };printf("please enter: ");scanf("%s", sbuffer);send(client_socket, sbuffer, strlen(sbuffer), 0);//立马接收char rbuffer[1024] = { 0 };int ret = recv(client_socket, rbuffer, 1024, 0);if (ret <= 0) break;printf("%s\n", rbuffer);}//4.关闭连接closesocket(client_socket);return 0;
}

tcp服务器客户端的重点在于服务端

因为存在的问题比较多:发送的消息怎么进行处理,如何同时接收多个客户端进行连接

3.实现多线程的客户端

服务端不应该主动断开连接而是由客户端断开

//连接一旦完成进入线程
        //Windows当中创建线程
        createThread(NULL,0,thread_func, &client_socket);
存在问题因为client_socket在栈区,所以可能socket销毁而线程都还没有启动(线程的运行是抢时间片的步骤,有可能线程在启动的时刻没抢过主线程,主线程已经把客户端socket销毁了)

所以我们要单独创建一个客户端socket,单独申请一个内存

服务端代码更改

#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")//定义一个线程函数 当做线程启动入口
DWORD WINAPI thread_func(LPVOID lpThreadParameter)
{//传入client_socket 解引用拿到后 释放地址SOCKET client_socket = *(SOCKET*)lpThreadParameter;free(lpThreadParameter);while (1) {//5.开始通讯(B/S) //通过浏览器访问一个网站的时候 //浏览器会发送一个http请求 http是tcp的上层协议 所以写tcp是可以接收http的报文的//接收发送的报文char buffer[1024] = { 0 };/*int recv(SOCKET s,	//客户端socketchar* buf,	//接受的数据存到哪里int len,	//接受的长度int flags	//0);*/int ret = recv(client_socket, buffer, 1024, 0);if (ret <= 0) break;printf("%llu:%s\n",client_socket, buffer);//回显 接收完之后立马发送回去send(client_socket, buffer, (int)strlen(buffer), 0);}//断开连接 打印一下printf("socket: %llu,disconnect.\n", client_socket);//6.关闭连接closesocket(client_socket);return 0;
}int main()
{//windows上使用网络功能需要开始网络权限WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);//1.创建socket套接字/*socket(int af,  //协议地址簇 ipv4/ipv6 对应 AF_INET/AF_INET6int type,	//类型	流式协议/帧式协议 对应 SOCK_STREAM/SOCK_DGRAMint protocol	//保护协议 tcp/udp不用填保护协议 直接填0);*///此处是服务端socket,所以我们一般起名叫监听socketSOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);//SOCKET是一个无符号的长整型,就是一个整数,可以直接打印出来//未开启网络结果为-1 即无效的socket -> INVALID_SOCKETif (INVALID_SOCKET == listen_socket) {printf("create listen socket failed !!! errocode: %d\n", GetLastError());return -1;}//2.给这个socket绑定一个端口号//struct sockaddr_in {//	ADDRESS_FAMILY sin_family;	//协议地址簇//	USHORT sin_port;	//端口号//	IN_ADDR sin_addr;	//IP地址//	CHAR sin_zero[8];	//保留字节 -> 协议升级会用//};//大小端问题://	一个数字在计算机中存储以二进制存储,对端口来讲占两个字节//	编程中最小单位我们通常用字节来算,很少用位算//	存数据的时候会有先后的问题 8080 -> 1F90(大端序号,高位放前面【千百个十】)//	但是本地电脑的存储方式是以小端序存储的【个十百千】//unsigned short a = 8080;//unsigned short* p = &a;struct sockaddr_in local = { 0 };local.sin_family = AF_INET;local.sin_port = htons(8080);	//大小端问题 中间设备使用的是大端序//服务端 选项 网卡 127.0.0.1(本地环回)只接受哪个网卡的数据//一般写0.0.0.0 不管哪个数据库来 只要有我都接受//INADDR_ANY整数 占4个字节//local.sin_addr.s_addr = htonl(INADDR_ANY);//手动指定local.sin_addr.s_addr = inet_addr("0.0.0.0"); //字符串IP转换成整数IP//绑定 给上面定义的socket绑定我们指定的内容/*int bind(SOCKET s,	//对哪个socket进行绑定const struct sockaddr FAR * name,	//sockaddr的结构int namelen	//长度);  返回整数类型*///为什么使用sockaddr结构而不是sockaddr_in结构?(两个结构体的大小一模一样)/*struct sockaddr {ADDRESS_FAMILY sa_family;CHAR sa_data[14];}   用这个方便扩展  通用的结构*/if (-1 == bind(listen_socket, (struct sockaddr*)&local, sizeof(local))) {printf("bind socket failed !!! errocode: %d\n", GetLastError());return -1;}//3.给socket开启监听属性/*int listen(SOCKET s,int backlog	//半连接队列长度);*/if (-1 == listen(listen_socket, 10)) {printf("start listen socket failed !!! errocode: %d\n", GetLastError());return -1;}//以上准备工作结束//4.等待客户端连接//返回的客户端socket才是跟客户端可以通讯的一个socket//listen_socket唯一的作用就是等待连接 最后返回一个socket出来//accept()是阻塞函数,等到有客户端连接进来就接受连接,然后染回,否则就阻塞/*SOCKET accept(SOCKET s,	//监听socketstruct sockaddr * addr,	//客户端的IP地址和端口号int * addrlen	//结构的大小  为什么是指针 因为可填可不填 要填就要和上面的addr都填);*///如果要跟多个客户端通讯 需要有while循环while (1){SOCKET client_socket = accept(listen_socket, NULL, NULL);if (INVALID_SOCKET == client_socket)continue;//有新的连接产生 打印一下printf("new connnet, socket: %llu\n", client_socket);//单独申请一个客户端SOCKET* sockfd = (SOCKET*)malloc(sizeof(SOCKET));*sockfd = client_socket;//连接一旦完成进入线程//Windows当中创建线程CreateThread(NULL,0,thread_func, sockfd, 0, NULL);}return 0;
}

代码实现

二.UDP

1.TCP与UDP服务端的不同之处

  1. Socket类型

    • TCP使用SOCK_STREAM类型,而UDP使用SOCK_DGRAM类型。
  2. 连接方式

    • TCP是面向连接的,需要通过connectlistenaccept函数建立连接。
    • UDP是无连接的,不需要建立连接,直接使用sendtorecvfrom函数发送和接收数据。
  3. 数据传输

    • TCP提供可靠的、有序的数据传输,保证数据完整性。
    • UDP提供不可靠的、无序的数据传输,可能丢包,但速度更快。
  4. 并发处理

    • TCP服务端通常需要为每个客户端连接创建一个线程或使用非阻塞I/O来处理并发。
    • UDP服务端通常在主循环中使用recvfromsendto处理所有客户端的数据,不需要为每个客户端创建线程。
    • (UDP服务端示例代码中没有使用线程,因为UDP是无连接的,通常不需要为每个客户端创建线程。如果需要处理大量并发UDP客户端,可以考虑使用线程池或非阻塞I/O。)
  5. 错误处理

    • TCP在建立连接时会进行错误处理,如连接失败会返回错误。
    • UDP在发送和接收数据时可能会遇到错误,如目标不可达等,需要在发送和接收时处理。
  6. 资源消耗

    • TCP由于需要维护连接状态,资源消耗相对较高。
    • UDP不需要维护连接状态,资源消耗相对较低。
  7. 适用场景

    • TCP适用于需要可靠传输的场景,如文件传输、网页浏览等。
    • UDP适用于对实时性要求高的场景,如视频会议、在线游戏等。

2.服务端代码

#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);SOCKET udp_socket = socket(AF_INET, SOCK_DGRAM, 0);if (INVALID_SOCKET == udp_socket) {printf("create UDP socket failed !!! errocode: %d\n", GetLastError());return -1;}struct sockaddr_in local = { 0 };local.sin_family = AF_INET;local.sin_port = htons(8080);local.sin_addr.s_addr = inet_addr("0.0.0.0");if (-1 == bind(udp_socket, (struct sockaddr*)&local, sizeof(local))) {printf("bind socket failed !!! errocode: %d\n", GetLastError());return -1;}printf("UDP server is running\n");while (1) {char buffer[1024] = { 0 };struct sockaddr_in client_addr;int addr_len = sizeof(client_addr);int ret = recvfrom(udp_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);if (ret > 0) {printf("Received from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);sendto(udp_socket, buffer, ret, 0, (struct sockaddr*)&client_addr, addr_len);  // Echo back}}closesocket(udp_socket);WSACleanup();return 0;
}

3.客户端代码

#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")int main()
{WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);// 1. 创建socket套接字(通过套接字连接到服务端)SOCKET client_socket = socket(AF_INET, SOCK_DGRAM, 0);if (INVALID_SOCKET == client_socket) {printf("create socket failed!!!\n");return -1;}// 2. 定义服务器地址struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// 3. 开始通讯 send recvwhile (1){char sbuffer[1024] = { 0 };printf("please enter: ");scanf("%s", sbuffer);// 发送数据到服务器sendto(client_socket, sbuffer, strlen(sbuffer), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));// 接收服务器回显char rbuffer[1024] = { 0 };int addr_len = sizeof(server_addr);int ret = recvfrom(client_socket, rbuffer, 1024, 0, (struct sockaddr*)&server_addr, &addr_len);if (ret <= 0) break;rbuffer[ret] = '\0'; // 添加字符串结束符printf("Received from server: %s\n", rbuffer);}// 4. 关闭socketclosesocket(client_socket);WSACleanup(); // 释放 Winsock 资源return 0;
}


http://www.ppmy.cn/embedded/118109.html

相关文章

mxnet同步机制

mxnet同步机制 在 MXNet 中&#xff0c;多个算子和多个内核&#xff08;kernel&#xff09;的同步机制依赖于 CUDA 流&#xff08;CUDA Streams&#xff09; 和 事件&#xff08;CUDA Events&#xff09;&#xff0c;以及其内部的 执行引擎&#xff08;Execution Engine&#…

AI 赋能大模型:从 ChatGPT 到国产大模型的角逐与发展契机

在当今科技飞速发展的时代&#xff0c;大模型作为人工智能领域的关键技术&#xff0c;正引发着深刻的变革。它们在自然语言处理、计算机视觉、语音识别等众多领域展现出了惊人的潜力&#xff0c;为各行各业带来了前所未有的机遇和挑战。本文将深入剖析大模型的技术原理、市场态…

25届秋招总结——保持自信、坚定选择

前言 好久不见&#xff01;博主已经快三个月没有更新啦&#xff0c;因为这三月一直在经历秋招&#xff0c;很幸运最后在国庆节前结束了秋招&#xff0c;可以回去好好过节喽&#xff0c;这里也简单和各位小伙伴分享一下我的秋招总结吧&#xff0c;希望也可以帮助到一些小伙伴&a…

Kotlin Android 环境搭建

Kotlin Android 环境搭建 1. 引言 Kotlin 已成为 Android 开发的官方语言之一,因其简洁、表达性强和易于维护的特点而受到广大开发者的喜爱。在本教程中,我们将详细介绍如何在您的计算机上搭建 Kotlin Android 开发环境。 2. 系统要求 在开始搭建 Kotlin Android 开发环境…

Linux标准IO(二)-打开、读写、定位文件

1.打开文件fopen 在前面所介绍的文件 I/O 中&#xff0c;使用 open()系统调用打开或创建文件&#xff0c;而在标准 I/O 中&#xff0c;我们将使用库函数fopen()打开或创建文件&#xff0c;fopen()函数原型如下所示&#xff1a; #include <stdio.h>FILE *fopen(const ch…

xpath在python的lxml库中使用

接上文 安装和导入 安装&#xff1a; pip install lxml 导入&#xff1a; from lxml import etree 解析字符串 对字符串解析得到一个<class lxml.etree._Element>对象 html etree.HTML(html_data) 执行xpath 返回值类型可能多种多样 result html.xpath("//…

第十章 【后端】商品分类管理微服务(10.9)——商品分类增删改查接口

10.9 商品分类增删改查接口 编写 controller 层 package com.yumi.etms.goods.controller;import com.baomidou.mybatisplus.core.metadata.IPage

速通LLaMA3:《The Llama 3 Herd of Models》全文解读

文章目录 概览论文开篇IntroductionGeneral OverviewPre-TrainingPre-Training DataModel ArchitectureInfrastructure, Scaling, and EfficiencyTraining Recipe Post-TrainingResultsVision ExperimentsSpeech Experiments⭐Related WorkConclusionLlama 3 模型中的数学原理1…