l8-d7 实现TCP通信

news2024/10/5 17:19:10

一、TCP服务器的实现(理论)

#include <sys/types.h>

#include <sys/socket.h>

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

        -domain: 指定通信域(通信地址族);

        -type: 指定套接字类型;

        -protocol: 指定协议;

套接字类型与协议

-type: 指定套接字类型

TCP唯一对应流式套接字,所以选择SOCK_STREAM(数据报套接字:SOCK_DGRAM)

-protocol: 指定协议

流式套接字唯一对应TCP,所以无需要指定协议,设为0即可

bind函数与通信结构体

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

        -sockfd:socket函数生成的套接字

        -addr:通信结构体

        -addrlen:通信结构体的长度

IPv4地址族结构体

struct sockaddr_in {

        sa_family_t    sin_family; /* 地址族: AF_INET */

        in_port_t      sin_port;   /* 网络字节序的端口号 */

        struct in_addr sin_addr;   /*IP地址结构体 */

};

/* IP地址结构体 */

struct in_addr {

        uint32_t       s_addr;     /* 网络字节序的IP地址 */

};

二、实现代码

优化前

服务端

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 5001
#define BACKLOG 5

int main(int argc, char *argv[])
{
	int fd, newfd;
	char buf[BUFSIZ] = {}; //BUFSIZ 8142
	struct sockaddr_in addr;
	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0){
		perror("socket");
		exit(0);
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = 0;
	/*绑定通信结构体*/
	if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
		perror("bind");
		exit(0);
	}
	/*设置套接字为监听模式*/
	if(listen(fd, BACKLOG) == -1){
		perror("listen");
		exit(0);
	}
	/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
	newfd = accept(fd, NULL, NULL);
	if(newfd < 0){
		perror("accept");
		exit(0);
	}
	printf("BUFSIZ = %d\n", BUFSIZ);
	read(newfd, buf, BUFSIZ);
	printf("buf = %s\n", buf);
	close(fd);
	return 0;
}

客户端

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 5001
#define BACKLOG 5
#define STR "Hello World!"

int main(int argc, char *argv[])
{
	int fd;
	struct sockaddr_in addr;
	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0){
		perror("socket");
		exit(0);
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	/*向服务端发起连接请求*/
	if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
		perror("connect");
		exit(0);
	}
	write(fd, STR, sizeof(STR) );
	printf("STR = %s\n", STR);
	close(fd);
	return 0;
}

优化后

服务端

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define BACKLOG 5    //BACKLOG为5,表示服务器端可以排队的最大客户端连接数

int main(int argc, char *argv[])
{
	int fd, newfd, ret;
	char buf[BUFSIZ] = {}; //BUFSIZ 8142  用于存储从客户端读取的数据
	struct sockaddr_in addr;    //存储服务器的地址信息
	
	if(argc < 3){    //检查命令行参数的数量是否小于3,如果是,则打印错误信息并退出程序。这是因为服务器需要两个命令行参数:服务器的IP地址和端口号。
		fprintf(stderr, "%s<addr><port>\n", argv[0]);
		exit(0);
	}

	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0);    //创建一个新的套接字
	if(fd < 0){                //AF_INET表示使用IPv4协议,SOCK_STREAM表示使用TCP协议
		perror("socket");
		exit(0);
	}
	addr.sin_family = AF_INET;        //使用IPv4协议
	addr.sin_port = htons( atoi(argv[2]) );    //将命令行参数中的端口号转换为整数,并使用htons函数将其转换为网络字节序,然后设置到addr结构体中的sin_port字段。
	if ( inet_aton(argv[1], &addr.sin_addr) == 0) {    //将命令行参数中的IP地址转换为网络字节序并设置到addr结构体中的sin_addr字段。如果转换失败,则打印错误信息并退出程序。
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}

	/*绑定通信结构体*/
	if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){    //调用bind函数将套接字fd绑定到地址信息addr
		perror("bind");
		exit(0);
	}
	/*设置套接字为监听模式*/
	if(listen(fd, BACKLOG) == -1){    //用listen函数将套接字fd设置为监听模式,并设置最大客户端连接数为BACKLOG
		perror("listen");
		exit(0);
	}
	/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
	newfd = accept(fd, NULL, NULL);    //调用accept函数接受客户端的连接请求,并返回一个新的套接字描述符newfd用于和客户端通信
	if(newfd < 0){
		perror("accept");
		exit(0);
	}
	while(1){
		memset(buf, 0, BUFSIZ);    //调用memset函数将buf数组中的所有元素都设置为0
		ret = read(newfd, buf, BUFSIZ);    //调用read函数从客户端套接字newfd读取数据,并将数据存储到buf数组中。read函数返回读取到的字节数,并将其存储到ret变量中
		if(ret < 0)    //如果read函数返回值小于0,表示读取数据失败
		{    
			perror("read");
			exit(0);
		}
		else if(ret == 0)    //如果read函数返回值等于0,表示客户端已经关闭了连接
			break;
		else
			printf("buf = %s\n", buf);
	}
	close(newfd);    //关闭客户端套接字和服务器套接字
	close(fd);
	return 0;
}

客户端

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define BACKLOG 5

int main(int argc, char *argv[])
{
	int fd;
	struct sockaddr_in addr;
	char buf[BUFSIZ] = {};

	if(argc < 3){
		fprintf(stderr, "%s<addr><port>\n", argv[0]);
		exit(0);
	}

	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0){
		perror("socket");
		exit(0);
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]) );
	if ( inet_aton(argv[1], &addr.sin_addr) == 0) {
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}

	/*向服务端发起连接请求*/
	if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){    //调用connect函数向服务器发起连接请求
		perror("connect");
		exit(0);
	}
	while(1){
		printf("Input->");
		fgets(buf, BUFSIZ, stdin);    //调用fgets函数从标准输入读取一行数据,并将其存储到buf数组中。
		write(fd, buf, strlen(buf) );    //调用write函数将buf数组中的数据发送给服务器。
	}
	close(fd);
	return 0;
}

makefile 

CC=gcc
CFLAGS=-Wall
all:client server

clean:
    rm client server

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

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

相关文章

0925hw

1.登录账号密码 void sign_in(FILE *fp)//注册 {char usrname[10];char pwd[12];printf("输入账户:");scanf("%s",usrname);printf("输入密码:");scanf(" %s",pwd);fprintf(fp,"%s %s\n",usrname,pwd);printf("注册成…

postgresql-常用日期函数

postgresql-常用日期函数 简介计算时间间隔获取时间中的信息截断日期/时间创建日期/时间获取系统时间时区转换 简介 PostgreSQL 提供了以下日期和时间运算的算术运算符。 获取当前系统时间 select current_date,current_time,current_timestamp ;-- 当前系统时间一周后的日…

Spring——Spring IOC原理

摘要 IoC 不是一种技术&#xff0c;只是一种思想&#xff0c;一个重要的面向对象编程的法则&#xff0c;它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象&#xff0c;从而导致类与类之间高耦合&#xff0c;难于测试&#xff1b;…

电脑dll修复精灵下载,一键修复(win系统)MSVCP100/110/120/140.dll丢失方法

今天&#xff0c;我将为大家分享关于电脑vcruntime140.dll丢失的5种修复方法。在我们的日常生活中&#xff0c;电脑出现问题是常有的事&#xff0c;而vcruntime140.dll丢失则是其中较为常见的一种问题。那么&#xff0c;什么是vcruntime140.dll?它有什么作用&#xff1f;又有多…

如何从任何苹果、Windows或安卓设备访问iCloud照片

本文介绍了如何在各种设备上访问iCloud照片库,包括iPhone和iPad、Mac、Windows PC和Android设备。说明适用于iOS 13及以上版本、iPadOS 13及以上、macOS Big Sur(10.16)和Catalina(10.15)、Windows 10或11以及Android 10。 从iPhone、iPod Touch和iPad访问iCloud照片 照…

Spring Boot @Validated 和Javax的@Valid配合使用

一、Validated 和Valid有什么用 Validation 和Valid 常常配合使用对传输的参数进行数据校验的注解&#xff0c;并通过配置全局异常处理器进行合理化的提示&#xff0c;增加用户的体验 并且Validated可以通过分组来指定什么时候触发什么样的参数校验&#xff08;这里看一下就行…

基于FPGA的FIR数字滤波器设计(quartus和vivado程序都有)。

基于FPGA的FIR数字滤波器设计&#xff08;quartus和vivado程序都有&#xff09;。 附&#xff1a; 1.配套quartus从MATLAB系数生成直到仿真成功说明文档。 2.配套仿真出波形&#xff08;图1&#xff09;的视频。

ShareCRM罗一立:立足香港联通国际,出海正当时

IDC数据显示&#xff0c;2022年中国企业级应用SaaS市场规模达41.6亿美元&#xff1b;而根据另一组数据&#xff0c;同一年全球SaaS市场规模已突破千亿美元。 一边是国内趋于白热化的竞争环境&#xff0c;一边是拥有广阔市场空间的海外“流奶与蜜之地”。近两年&#xff0c;出海…

手写Mybatis:第14章-解析和使用ResultMap映射参数配置

文章目录 一、目标&#xff1a;ResultMap映射参数二、设计&#xff1a;ResultMap映射参数三、实现&#xff1a;ResultMap映射参数3.1 工程结构3.2 ResultMap映射参数类图3.3 添加类型处理器3.3.1 日期类型处理器3.3.2 类型处理器注册机 3.4 存放映射对象3.4.1 结果标志3.4.2 结…

数据结构笔记:PR四叉树

1 基本介绍 在PR四叉树中&#xff0c;每个节点代表一个矩形区域&#xff0c;并且每个节点要么没有子节点&#xff0c;要么有四个子节点&#xff0c;分别代表该矩形区域的四个象限 2 数据结构 PR四叉树的每个节点通常包含以下几个元素&#xff1a; 区域&#xff08;矩形&…

go语言基本操作--四

面向对象编程 对于面向对象编程的支持go语言设计得非常简洁而优雅。因为&#xff0c;Go语言并没有沿袭面向对象编程中诸多概念&#xff0c;比如继承(不支持继承&#xff0c;尽管匿名字段的内存布局和行为类似继承&#xff0c;但它并不是继承)、虚函数、构造函数和析构函数、隐…

16字节协议的串口通信

1.协议要求 协议为帧传输&#xff0c;一共16字节。主要是2字节的固定帧头 EB 90&#xff0c;2字节的帧计数(用来计数发出的帧),10字节的数据和2字节的校验位 帧头&#xff1a;2字节&#xff0c;固定值 8’HEB、8’H90 帧计数&#xff1a;2字节&#xff0c;用来说明发出去帧是…

esp32s3实现openmv

演示参考下方视频 源码链接在视频末尾获取点击查看视频 摄像头引脚配置 烧录配置

【Linux】进程基础概念【下篇】

目录 1. 基本概念 2. 常见环境变量 常见环境变量指令 &#xff08;1. PATH &#xff08;2. HOME &#xff08;3. SHELL 3.环境变量的组织形式 &#xff08;1&#xff09;通过代码如何获取环境变量 &#xff08;2&#xff09;普通变量与环境变量的区别 &#xff08;3&…

Vue+NodeJS实现邮件发送

一.邮箱配置 这里以QQ邮箱为例,网易邮箱类似. 设置->账号 二.后端服务搭建 index.js const express require(express) const router require(./router); const app express()// 使用路由文件 app.use(/,router);app.listen(3000, () > {console.log(server…

大学大创项目:手机室内AR导航APP项目思路

文章目录 一、最初的项目思路二、建图和定位分离的项目思路1、建图2、定位 个人见解&#xff0c;如有错误&#xff0c;请多包涵 一、最初的项目思路 在大创项目的开始&#xff0c;将手机确定为应用设备&#xff0c;传感器确定为相机。 由于知识储备的原因&#xff0c;在头一次…

Jenkins实现基础CI操作

操作截图 代码push进gitlab Jenkins拉取gitlab代码 在容器内Jenkins拉取的代码

app备案ios的公钥和md5的获取方法

最近app需要备案才能上架了 但是app备案的时候&#xff0c;特别是ios备案的时候需要提供app的公钥和md5比较头大&#xff0c;无论是android系统还是ios系统&#xff0c;都需要提供证书的公钥和md5。 获取这个公钥和md5真的好麻烦&#xff0c;好像各种工具都没有提供获取这些信…

java数据结构1------深入学习ArrayList

目录 一、概念 二、源码分析 1、属性 2、构造器 ①空构造 ②指定初始容量&#xff08;initialCapacity&#xff09;构造器 ②参数为Collection的构造器 3、常用方法 ①public boolean add(E e) ②public void add(int index, E element) ③其他方法 三、总结 一、概念…

【ARM AMBA5 CHI 入门 12 -- CHI 总线学习 】

文章目录 介绍CHI 特点Layers of the CHI architectureTopology Node TypeTransaction 分类Transaction 路由SAM 介绍Node ID 节点间数据怎么传输的呢&#xff1f; 介绍 CHI 的全称是 Coherent Hub Interface。所以从名字就能看出&#xff0c;CHI要解决什么问题了。按照惯例&a…