网络编程:TCP和UDP

news2025/1/19 11:17:42

一、通信模式

1.1 套接字socket

1.网络通信通过套接字进行数据传输

2.socket是一个函数,为通信创建一个端点,并返回该端点的文件描述符

3.套接字本身是一个文件描述符,对应的是一个特殊的文件,该文件描述符维护了两个缓冲区,分别是发送缓冲区和接收缓冲区

4.套接字可以实现全双工的通信

int socket(int domain, int type, int protocol);

功能:创建用于通信的一个端点,并返回对应的文件描述符,文件描述符按最小未使用原则分配 参数1:规定通信域

        AF_UNIX, AF_LOCAL     同一主机之间多进程通信      具体内容可查看 man 7 unix

        AF_INET IPv4                 网络通信                                具体内容可查看 man 7 ip

参数2:传输方式或类型

SOCK_STREAM     支持TCP通信方式

SOCK_DGRAM       支持UDP通信方式

SOCK_RAW            支持原始套接字通信

参数3:协议

如果第二参数指定了SOCK_STREAM或SOCK_DGRAM则第三个参数填0

如果第二个参数为SOCK_RAW,则第三个参数需要指定对应的协议

        对于TCP通信:IPPROTO_TCP

        对于UDP通信:IPPROTO_UDP

返回值:成功返回创建出的套接字文件描述符,失败返回-1并置位错误码

二、TCP通信

2.2相关API

bind:绑定端口号和IP地址

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

listen:启动被动监听

int listen(int sockfd, int backlog);

accept :阻塞等待客户端的连接请求

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

send/recv:数据发送和接收函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

connect:连接函数

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

2.3TCP服务器代码

#include <head.h>

#define SER_PORT 8888           //服务器端口号
#define SER_IP "192.168.117.94"//服务器IP
int main(int argc, const char *argv[])
{
	//1.创建一个套接字
	int sfd=socket(AF_INET,SOCK_STREAM,0);
//
	if(sfd==-1){
		perror("socket");
		return -1;
	}
	printf("%d sfd=%d\n",__LINE__,sfd);
	//主动去连接别人
	//2.绑定ip地址和端口号
	//2.1填充地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family=AF_INET; //地址族   IPV4网络通信
	sin.sin_port=htons(SER_PORT);//端口号   将主机字节序转换为网络字节序
	sin.sin_addr.s_addr=inet_addr(SER_IP);//ip地址 将点分十进制的ip地址转换为4字节无符号整数的网络字节序

	//2.2绑定
	if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))==-1){
		printf("bind");
		return -1;
	}
	printf("%d bind success\n",__LINE__); 
	
	//将套接字设置成被动监听状态
	if(listen(sfd,128)==-1){
		perror("listen");
		return -1;
	}
	printf("%d listen success\n",__LINE__);

	//4.阻塞等待客户端的连接请求
	int newfd=-1;
	//定义结构体变量接受对方地址信息结构体
	struct sockaddr_in cin;//用于接收客户端地址信息结构体
	socklen_t addrlen =sizeof(cin);//用于接收客户端结构体的大小
	if((newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen))==-1){ //阻塞等待客户端的连接请求
		perror("accept");
		return -1;
	}
	printf("%s  %d:发来连接请求\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
	//                      将网络字节序转换为十进制的字符串(ip地址)  网络字节序转换成主机字节序(端口号)

	//5.收发数据
	char rbuf[128]="0";//用于接收客户发来的数据
	while(1){
		//将容器清空
		bzero(rbuf,sizeof(rbuf));//memset(rbuf,0,sizeof(rbuf));
		//从套接字重读取数据
		int res=recv(newfd,rbuf,sizeof(rbuf)-1,0);
		if(res==0){
			printf("客户端已经下线\n");
			break;
		}
		printf("%s  %d:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);

		//加个笑脸再发回去
		strcat(rbuf,"*_*");
		send(newfd,rbuf,strlen(rbuf),0);
		printf("发送成功\n");
	}


//6.关闭服务器
close(newfd);
close(sfd);
	return 0;
}

2.4TCP客户端代码

#include <head.h>

#define SER_PORT 7777
#define SER_IP "192.168.117.96"
#define CLI_PORT 6666
#define CLI_IP "192.168.117.96"
int main(int argc, char const *argv[])
{
    //1.创建用于连接的客户端套接字
    int cfd=socket(AF_INET,SOCK_STREAM,0);
    if(cfd==-1){
        perror("socket");
        return -1;
    }
    printf("socet success cfd=%d\n",cfd);

    //设置端口号快速重用
    int reuse = 1;
    if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ==-1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");

    //2.绑定端口号和ip地址(非必须) 如果不写的系统会随机给
    //2.1填充客户端地址信息结构体
    struct sockaddr_in cin;
    cin.sin_family=AF_INET;
    cin.sin_port=htons(CLI_PORT);
    cin.sin_addr.s_addr=inet_addr(CLI_IP);

    //2.2绑定端口号和IP
    if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))==-1){
        perror("bind");
        return -1;
    }
    printf("bind success\n");

    //3.连接服务器
    //3.1填充要连接服务器的地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family=AF_INET;//地址族
    sin.sin_port=htons(SER_PORT);//服务器端口号
    sin.sin_addr.s_addr=inet_addr(SER_IP);//服务器的IP地址

    //3.2连接服务器
    if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1){
        perror("connect");
        return -1;
    }
    printf("连接成功\n");

    //4.收发数据
    char wbuf[128]="0";
    while(1){
        printf("请输入>>>");
        fgets(wbuf,sizeof(wbuf),stdin);//从终端上获取一个字符串
        wbuf[strlen(wbuf)-1]='\0';//将换行换成'\0'

        //判断输入的字符串值
        if(strcmp(wbuf,"quit")==0)
            break;
        //将数据发送给服务器
        send(cfd,wbuf,strlen(wbuf),0);

        //将字符数组清空
        bzero(wbuf,sizeof(wbuf));
        recv(cfd,wbuf,sizeof(wbuf)-1,0);
        printf("收到服务器消息为%s\n",wbuf);

    }
    //5.关闭套接字
    close(cfd);

    return 0;
}

2.5效果演示

三、UDP通信

3.1通信模型

3.2相关API

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

功能:从套接字文件描述符中读取len个字节的数据,将数据放入buf起始地址的容器中,并接收对端的地址信息结构体

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

功能:向对端套接字中发送数据

3.3UDP服务器代码

#include <head.h>
#define SER_PORT 6666
#define SER_IP "192.168.118.60"


int main(int argc, const char *argv[])
{
    //1、创建用于通信的套接字文件描述符
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("socket success sfd = %d\n", sfd);        //3
    
    //设置端口号快速重用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ==-1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");


    //2、绑定IP地址和端口号
    //2.1填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
    //2.2 绑定
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    
    //3、数据收发
    char rbuf[128] = "";

    //定义接收对端地址信息结构体的容器
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);

    while(1)
    {
        //清空容器
        bzero(rbuf, sizeof(rbuf));

        //接收数据
        recvfrom(sfd, rbuf, sizeof(rbuf)-1, 0, (struct sockaddr*)&cin, &addrlen);
        printf("[%s:%d] :%s\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);

        //连接一个笑脸回过去
        strcat(rbuf, "*_*");
        if(sendto(sfd, rbuf, strlen(rbuf), 0, (struct sockaddr*)&cin, sizeof(cin)) == -1)
        {
            perror("write error");
            return -1;
        }
    }
    
    //4、关闭套接字
    close(sfd);

    return 0;
}

3.4UDP客户端代码

#include <head.h>
#define SER_PORT 6666
#define SER_IP "192.168.118.60"
#define CLI_PORT 7777
#define CLI_IP "192.168.118.60"


int main(int argc, const char *argv[])
{
    //1、创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("socket success cfd = %d\n", cfd);
    
    //2、绑定IP地址和端口号
    //2.1 填充客户端地址信息结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;
    cin.sin_port = htons(CLI_PORT);
    cin.sin_addr.s_addr = inet_addr(CLI_IP);
    //2.2 绑定
    if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success\n");
    
    
    //3、数据收发
    char wbuf[128] = "";
    //填充要发送的对端的地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);

    while(1)
    {
        printf("请输入>>>");
        fgets(wbuf, sizeof(wbuf), stdin);    //从终端获取一个字符串
        wbuf[strlen(wbuf)-1] = 0;          //将换行换成'\0'

        //判断输入的是否为退出
        if(strcmp(wbuf, "quit") == 0)
        {
            break;
        }
        
        //将数据发送给服务器
        sendto(cfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&sin, sizeof(sin));

        printf("发送成功\n");

        //接收服务器发来的消息
        bzero(wbuf, sizeof(wbuf));

        read(cfd, wbuf, sizeof(wbuf)-1);
        printf("收到服务器消息为:%s\n", wbuf);

    }

    //4、关闭套接字
    close(cfd);

    return 0;
}

3.5效果演示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1518607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是分段锁?

1、典型回答 分段锁是一种将锁细化到每个段(Segment) 级别的锁设计。在 ConcurrentHashMap 中&#xff0c;它将整个数据结构分成多个段&#xff0c;每个段只锁定自己的一部分数据。每个段可以看作是一个独立的分组&#xff0c;只锁定该段(Segment)内部的数据操作&#xff0c;不…

以题为例浅谈SSRF

什么是ssrf SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能够请求到与它相连…

C语言指针与数组(不适合初学者版):一篇文章带你深入了解指针与数组!

&#x1f388;个人主页&#xff1a;JAMES别扣了 &#x1f495;在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. &#x1f60d;希望我的文章对大家有着不一样的帮助&#xff0c;欢迎大家关注我&#xff0c;我也会回…

python 基础知识点(蓝桥杯python科目个人复习计划63)

今日复习内容&#xff1a;做题 例题1&#xff1a;蓝桥骑士 问题描述&#xff1a; 小蓝是蓝桥王国的骑士&#xff0c;他喜欢不断突破自我。 这天蓝桥国王给他安排了N个对手&#xff0c;他们的战力值分别为a1,a2,...,an&#xff0c;且按顺序阻挡在小蓝的前方。对于这些对手小…

Java NIO浅析

NIO&#xff08;Non-blocking I/O&#xff0c;在Java领域&#xff0c;也称为New I/O&#xff09;&#xff0c;是一种同步非阻塞的I/O模型&#xff0c;也是I/O多路复用的基础&#xff0c;已经被越来越多地应用到大型应用服务器&#xff0c;成为解决高并发与大量连接、I/O处理问题…

矿洞隧道漫游可视化:探索地心深处的奇幻世界

在这个充满好奇与探索的时代&#xff0c;我们总是渴望揭开世界的神秘面纱&#xff0c;探寻那些深藏在地球内部的奥秘。 矿洞隧道漫游可视化系统通过先进的计算机图形学、虚拟现实和三维建模技术&#xff0c;将矿洞隧道的真实场景进行高精度还原&#xff0c;让我们仿佛置身于一个…

leetcode判断子序列

本题中&#xff0c;我们可以删除原始字符串的一些字符但是不能改变其他字符的位置&#xff0c;这种求子序列的题都可以用动态规划来解决。 首先我们要确定dp数组的定义&#xff0c;这里我们将dp数组定义为dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的…

Cadence PCB布线时的电源地操作

一般在布线时需要先将GND、3.3V、5V、24V电源和地等进行处理&#xff0c;使得在打开飞线后不至于太凌乱。 效果如下&#xff1a; 1. 方法如下&#xff1a; 之后打开飞线即可显示设置效果。 2. 至于如何删除&#xff1f;&#xff1f;&#xff1f; 勾选delete&#xff0c;应用即…

如何选择多域名SSL证书?

多域名SSL证书&#xff0c;顾名思义&#xff0c;是一种特殊的SSL证书&#xff0c;它允许同时保护多个域名及其子域名的安全。与传统的单域名SSL证书相比&#xff0c;多域名SSL证书就像是一把万能钥匙&#xff0c;能够开启多个不同的锁&#xff0c;为多个网站提供一把坚固的安全…

【机器学习】机器学习是什么?用在哪里?怎么用?

1.机器学习是什么&#xff1f; 机器学习&#xff08;Machine Learning&#xff09;是人工智能的一个分支&#xff0c;它是一种通过对数据进行训练和学习&#xff0c;让计算机系统从中获取知识并改善性能的方法。简而言之&#xff0c;机器学习使计算机具有从数据中学习并自动改…

垃圾分类网站 |基于springboot框架+ Mysql+Java+B/S结构的垃圾分类网站 设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参考 摘要 研究…

重生奇迹mu元素合成流程

1、元素之魂是通过元素之心和艾丽亚之环合成的&#xff0c;在NPC阿德尼这里可以合成&#xff0c;NPC在精灵地图&#xff0c;而元素之心碎片和艾丽亚之环碎片的掉落也是在是在精灵地图。 2、玩家获得材料后&#xff0c;需经过2阶段的精炼才会成为可使用的元素之魂。各精炼阶段的…

在线动漫信息平台|基于springboot框架+ Mysql+Java+B/S架构的在线动漫信息平台设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 会员后台功能 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen…

Docker 哲学 - 容器操作

容器&#xff1a; 创建 停止 删除 强制删除&#xff08;正在运行&#xff09; run stop rm rm -f 列出本地容器&#xff1a; docker ps / docker container ls 镜像&#xff1a; search pull run &#xff1a; …

MySQL Connector连接失败之SSL connection error: protocol version mismatch

调用 mysql_real_connect&#xff08;&#xff09; 连接失败&#xff0c;报错为ERROR 2026 (HY000): SSL connection error: protocol version mismatch 调用mysql_error&#xff08;&#xff09;查看失败原因&#xff0c;结果为 SSL connection error: protocol version …

Bugku MISC做题笔记

简单套娃DX 这一题需要对png图片的结构有所了解。详细可参考https://www.w3.org/TR/png/ 幸好每一张图片只有一个错误&#xff0c;逐步调试&#xff0c;就可以发现所有错误&#xff0c;修正即可。具体错误参看python程序中的注释&#xff1a; import ossrc_dir .\\XD\\ de…

7-Eleven用工数字化:零售哲学下的人效管理实践

2014年&#xff0c;一本《零售的哲学》在中国掀起热潮&#xff0c;揭示了7-Eleven便利店的新零售坪效管理秘诀。而对大部分零售企业来说&#xff0c;劳动力效率是坪效背后的主要支柱。近期&#xff0c;国内领先的劳动力管理云服务提供商盖雅工场发布了《聚焦人效、重塑组织&…

香港理工大学主办!2024年第八届电力能源系统与应用国际会议(ICoPESA 2024)即将召开!

2024年第八届电力能源系统与应用国际会议&#xff08;ICoPESA 2024&#xff09; 2024年6月24日-26日 中国香港 ICoPESA 2024-Hong Kong (icpesa.org)https://icpesa.org/index.html 会议组织单位 会议出版及检索&#xff1a; 会议录用并注册的论文将由IEEE出版&#xff0c;…

聚酰亚胺PI材料难于粘接,用什么胶水粘接?那么让我们先一步步的从认识它开始(一)

聚酰亚胺PI的基本概念 聚酰亚胺&#xff08;Polyimide&#xff0c;简称PI&#xff09;是一种重要的高性能聚合物材料。是指主链上含有酰亚胺环的一类聚合物&#xff0c;是综合性能最佳的有机高分子材料之一。它具有最高的阻燃等级&#xff08;UL-94&#xff09;&#xff0c;以及…

OpenCV 将rgb图像转化成字符图像

将RGB图像转换成字符图像&#xff08;ASCII art&#xff09;通常涉及到灰度化、降采样、映射字符等一系列步骤。以下是一个简化的OpenCVC实现示例&#xff1a; #include <opencv2/opencv.hpp> #include <iostream> #include <string>// 字符映射表&#xff…