首页 > 编程语言 >网络编程练习题---利用TCP协议完成客户端与服务端点对点通信

网络编程练习题---利用TCP协议完成客户端与服务端点对点通信

时间:2024-06-05 20:33:44浏览次数:12  
标签:练习题 addr errno TCP --- tcp 客户端 include socket

目录

题目一

设计程序实现解析www.baidu.com的域名,把获取到的百度的IP地址全部输出到终端并验证是否正确。

解析

主机打算响应某个网站的网络请求,但是只知道网站域名是无法通信的,需要对域名进行地址解析,得到网站的公有IP地址,所以Linux系统提供了名称叫做gethostbyname()的函数接口实现该功能,使用规则如下:

image

代码实现

/********************************************************************************
*
*	file name:	demo_domain.c
*	author	 :  [email protected] 
*	date	 :  2024/06/04
*	function :  
*               设计程序实现解析www.baidu.com的域名,
*               把获取到的百度的IP地址全部输出到终端并验证是否正确。
* 	note	 :  
*               1.可以通过ping 百度域名,观察返回值的IP地址来验证获取值是否正确
*               2.通过命令行输入不同的域名,来获取不同域名的IP地址
*                 例如:./xxx xxx(有效域名地址)
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   All Right Reseverd 
*
* ******************************************************************************/
/****************************头文件*********************************************/
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    //对参数进行错误处理
    if(argc != 2)
    {
        fprintf(stderr, "argc error, errno: %d, %s\n", errno, strerror(errno));
        exit(1);
    }

    //利用gethostbyname函数接口,获取目标域名所包含的信息
    struct hostent *hostent =  gethostbyname(argv[1]);

    //定义一个结构体变量,用于存储IP地址
    struct in_addr ip_hostent;
    //定义一个循环数组下标
    int i = 0;

    //循环将获取得到的hostent结构体中的ip地址转换为点分十进制字符串输出
    while(hostent->h_addr_list[i] != NULL)
    {
        //将获取IP地址进行类型转换,存储在ip_hostent中
        ip_hostent.s_addr = *(uint32_t *)(hostent->h_addr_list[i]);

        //利用函数接口inet_ntoa(),将网络节序类型转换为点分十进制字符串类型并输出
        printf("%s ip :%s\n", argv[1], inet_ntoa(ip_hostent));

        //对数组下标进行偏移
        i++;
    }

    return 0;
}

题目二:

利用TCP协议,设计两个程序,一个作为客户端,先发送连接申请给服务端,发送消息给服务端;另一个作为服务端,接受客户端申请,并接受客户端发送的消息。

解析

  1. listen函数不具有阻塞特性,因为listen只是相当于把socket的属性更改为被动连接,可以接收其他进程的连接,设置好后便会返回,监听的实质有操作系统完成。
  2. 调用listen函数需要设置监听队列的最大容量,该监听队列容量不是指的是服务端能连接客户端的数量。
  3. accept函数具有阻塞特性,调用一次accept只能接收一个客户端申请请求,并且会生成返回一个新的、专属于当前连接的客户端的文件描述符,该描述符一定要存储起来,方便服务端后续与客户端点对点通信。

代码实现

tcp_client.c

/********************************************************************************
*
*	file name:	tcp_client.c
*	author	 :  [email protected] 
*	date	 :  2024/06/05
*	function :  该案例是掌握TCP协议通信方式,该代码文件将实现客户端发送信息给服务端的功能。
* 	note	 :  
*				1. 需要注意的是connect是非阻塞特性,所以一定要接收返回值进行判断,
*				   否则会出现没有连接成功,却进入发送的错误状态。
*				2. 由于该函数部分参数由命令行传入,所以在执行文件时要加上参数
*				   例如:./xxx  xxx(端口号) xxx.xxx.xxx.xxx(服务端IP地址--点分十进制)
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   All Right Reseverd 
*
* ******************************************************************************/
/****************************头文件*********************************************/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc,const char *argv[])
{
	//判断命令行参数
	if(argc != 3)
	{
		fprintf(stderr, "argc error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	//创建TCP的套接字文件
	int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
	if(tcp_socket == -1)
	{
		fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(2);
	}

	//绑定本地信息--如果只打算实习发送功能,该步骤也可以省略
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 						//协议族,为固定宏
	host_addr.sin_port   		= htons(atoi(argv[1]));			//想要接收信息进程的端口号
	host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);			//本地地址,填写该宏定义代表任意网口都可以接收值

	bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

	//向目标主机发送消息,需要设置目标端口和目标地址
	char buf[128] = {0};

	struct sockaddr_in  dest_addr;
	socklen_t flag_dest = sizeof(dest_addr);

	dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	dest_addr.sin_port   		= htons(atoi(argv[1]));			//服务器运行进程的端口号,必须转换为网络字节序
	dest_addr.sin_addr.s_addr   = inet_addr(argv[2]);			//要发送对象的IP地址,必须转换为点分十进制字符串形式

	//使用connect函数接口向服务器发起连接申请
	int flag_connect = connect(tcp_socket, (struct sockaddr *)&dest_addr, flag_dest);
	if(flag_connect == -1)
	{
		fprintf(stderr, "connect socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(3);
	}

	//循环向服务器发送消息
	while(1)
	{
		//从键盘获取信息
		scanf("%s", buf);
		write(tcp_socket, buf, strlen(buf));
		bzero(buf, sizeof(buf));
	}

	return 0;
}

tcp_server.c

/********************************************************************************
*
*	file name:	tcp_server.c
*	author	 :  [email protected] 
*	date	 :  2024/06/17
*	function :  该案例是掌握进行模块化编程思想,以及封装函数接口流程
* 	note	 :  
*				1. 需要注意的是listen是非阻塞特性,accept才具有阻塞特性
*				2. accpet在成功连接客户端后,会重新创建一个新的、专属于连接客户端的
*				   套接字文件描述符,方便服务端与客户端点对点通信
*				3. 由于该函数部分参数由命令行传入,所以在执行文件时要加上参数
*				   例如:./xxx  xxx(端口号)
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   All Right Reseverd 
*
* ******************************************************************************/
/****************************头文件*********************************************/
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
	//对命令行传入参数数量进行判断
	if(argc != 2)
	{
		fprintf(stderr, "argc error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	//1.创建TCP套接字
	int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (tcp_socket == -1)
	{
		fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(2);
	}

	//2.绑定自身的IP地址和端口,由于该处服务器功能是接受信息,所以一定要绑定自身信息
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	host_addr.sin_port   		= htons(atoi(argv[1]));			//目标端口,必须转换为网络字节序
	host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);		    //目标地址  INADDR_ANY 这个宏是一个整数,所以需要使用htonl转换为网络字节序

	bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

	//3.设置监听,且监听队列最大容量设置为5
	listen(tcp_socket,5);

	//4.等待接受客户端的连接请求
	struct sockaddr_in  client;
	socklen_t client_len = sizeof(client);

	//调用accept函数接口后,一定要接收其返回值,因为该返回值为accept创建的新的、专属于连接客户端的套接字文件描述符
	int connect_fd = accept(tcp_socket,(struct sockaddr *)&client,&client_len); //会阻塞
	char buf[128] = {0};

	//5.说明双方建立连接,此时可以接收数据
	while(1)
	{
		read(connect_fd,buf,sizeof(buf));
		printf("recv from [%s],data is = %s\n", inet_ntoa(client.sin_addr) ,buf);
		bzero(buf,sizeof(buf));
	}

	return 0;
}

标签:练习题,addr,errno,TCP,---,tcp,客户端,include,socket
From: https://www.cnblogs.com/fly-home/p/18233736

相关文章

  • 【YOLOv8改进】D-LKA Attention:可变形大核注意力 (论文笔记+引入代码)
    YOLO目标检测创新改进与实战案例专栏专栏目录:YOLO有效改进系列及项目实战目录包含卷积,主干注意力,检测头等创新机制以及各种目标检测分割项目实战案例专栏链接:YOLO基础解析+创新改进+实战案例摘要医学图像分割在Transformer模型的应用下取得了显著进步,这些模型在捕......
  • 前端-Vue 快速上手
    Vue概念:Vue是一个用于构建用户界面的渐进式框架①构建用户界面:基于数据动态渲染页面②渐进式:循环渐进的学习③框架:一套完整的项目解决方案,提升开发效率↑(理解记忆规则)   规则→官网(v2.cn.vuejs.org / cn.vuejs.org)Vue的两种使用方式:1.Vue核......
  • RabbitMQ tutorial - "Hello world!"
    RabbitMQtutorial-"Helloworld!"本例阻塞线程方式一生产者一消费者依赖项abbitMQisinstalledrunningonlocalhostonthestandardport(5672).理解RabbitMQisamessagebroker:itacceptsandforwardsmessages.Youcanthinkaboutitasapostoffic......
  • 在Windows上安装mysql-8.0.28-winx64.zip
    1.解压2.配置文件点击查看代码MicrosoftWindows[版本10.0.17763.316](c)2018MicrosoftCorporation。保留所有权利。D:\mysql\bin>mysqldinstallmysql8Servicesuccessfullyinstalled.D:\mysql\bin>mysqld--initialize-insecureD:\mysql\bin>mysql-uroot......
  • Android应用程序启动源码浅析-(三万字长文慎点&Android14)
    在Android桌面Launcher源码浅析中介绍了Android的桌面程序Launcher是如何响应用户点击事件并启动App的,这篇文章继续介绍App在Android系统层的启动流程。一、启动流程sequenceDiagramparticipantUserparticipantLauncherparticipantActivityManagerService......
  • 基于c语言的TCP客户端、服务端基础代码
    基于c语言的TCP客户端、服务端基础代码基本流程:客户端:#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<stdio.h>#include<errno.h>#include<sys/socket.h>#include<netinet/in.h>#include<netinet/......
  • DP读书:《半导体物理学(第八版)》(七) 金属与半导体的接触- 10 min 速通(载流子分布)
    《半导体物理学(第八版)》10min速通金属与半导体的接触7.1金属与半导体的接触及其能带图7.1.1金属和半导体的功函数7.1.2接触电势差7.1.3表面态对接触势垒的影响7.2金属半导体接触整流理论7.2.1扩散理论7.2.2热电子发射理论7.2.3镜像力和隧道效应的影响7.2.4......
  • 【linux-IMX6ULL-pinctrl和gpio子系统】
    目录1.pinctrl子系统1.1pinctrl子系统简介1.2pinctrl子系统使用1.2.1追加pin节点1.2.2配置引脚信息节点2.GPIO子系统2.1GPIO子系统简介2.1gpio子系统API函数3.检查PIN是否被其他外设使用1.pinctrl子系统1.1pinctrl子系统简介  pinctrl和gpio子系......
  • [职业教育核心管理平台]技术白皮-常见任务的PC端操作方法
    A.授课教师角色常见任务PC端操作:1.所授课程教材信息录入:2.授课班级信息的查询3.授课班级学生信息查询4.授课日志现场操作操作时间点:5.导出授课日志记录操作时间点:6.上课日志模板准备操作时间点:7.所授课程分数录入操作时间点:6.所授课程分数查询  B.班主任......
  • 大型ERP设计-业务与功能指引:委托加工二(有偿供料)
    委托加工二(有偿提供材料)前言:在对ORACLE和SAP的核心模块功能全面解读的基础上,给出大型ERP设计的建议-业务与功能指引,企业选型、开发大型ERP软件的公司和ERP顾问可以参考。模块包括财务、计划与制造、供应链、项目及设备(MRO),初步预计涉及大约500个以上功能点,最终会形成大型ERP......