简单TCP编程

2023-05-16

1.TCP服务端

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

#define SERV_PORT 5001

//本机合法IP地址
#define SERV_IP "192.168.9.30 "


int main()
{
	//1.创建流式套接字
	int listenFd = socket( AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf( "socket ok!\n" );
	
	//2.绑定本机IP地址和端口号
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );
	
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);
	sin.sin_addr.s_addr = inet_addr(SERV_IP);
	
	int ret = bind(listenFd, (struct sockaddr *)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror( "bind" );
		exit(1);
	}
	printf("bind ok!\n");
	
	//3.设置监听套接字
	ret = listen(listenFd, 5);
	if(ret < 0){
		perror("listen");
		exit(1);
	}
	printf("listen ok!\n");
	
	//4.等待客户端连接
	int connFd = accept(listenFd, NULL, NULL );
	if(connFd < 0){
		perror("accept");
		exit(1);
	}
	printf("accept ok!\n");
	
	//5.接受/发送消息
	char buf[BUFSIZ];
	
	while(1){
		memset( buf, 0, sizeof(buf) );
		ret = recv( connFd, buf, sizeof(buf)-1, 0 );
		if( ret < 0 ){       //出错
			perror( "recv" );
			continue;
		}
		if( 0 == ret){       //对端关闭套接字
			printf("client closes the socket!\n");
			break;
		}
		printf("recv:%s\n", buf);
	}
	
	//6.关闭套接字
	close(listenFd);
	close(connFd);
	
	return 0;
}

1.1TCP服务端优化

1.等待连接加循环,修改关闭套接字

2.地址端口快速重用,不用等MSL,就可重连
	int on = 1;
	setsockopt ( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

setsockopt() 设置 SO_REUSEADDR 选项。该选项允许在 bind() 函数中使用已被其他 socket 使用的地址.

具体来说,当一个 socket 被关闭后,它所占用的端口号将会被系统保留一段时间,以确保任何可能延迟到达的数据都能够被传递完毕。

如果在这段时间内有一个新的 socket 尝试绑定到同样的端口上,就会出现 “Address already in use” 错误。

第二个参数SOL_SOCKET 指定了要设置的 socket 层面的选项,

 "socket options level""socket 选项级别" 的意思。

第三个参数 SO_REUSEADDR 指定了要设置的选项名称,
第四个参数 &on 是一个指向选项值的指针,用于设置选项的值为 1(打开选项)
最后一个参数 sizeof(on) 是选项值的大小。

返回值为 0,则表示操作成功;
返回值为 -1,则表示操作失败,可以使用 errno 变量来查看具体的错误信息。

3.IP地址不用改

4.显示连接的客户端的地址

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

#define SERV_PORT 5001

int main()
{
	//1.创建流式套接字
	int listenFd = socket( AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf( "socket ok!\n" );

	//优化2:允许地址和端口号快速重用
	int on = 1;
	setsockopt( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

	//2.绑定本机IP地址和端口号
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );

	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);

	//优化3:IP地址绑到0.0.0.0(全0监听,即本机所有网卡所有IP)
	sin.sin_addr.s_addr = htonl( INADDR_ANY );

	int ret = bind(listenFd, (struct sockaddr *)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror( "bind error" );
		exit(1);
	}
	printf("bind ok!\n");

	//3.设置监听套接字
	ret = listen(listenFd, 5);
	if(ret < 0){
		perror("listen error");
		exit(1);
	}
	printf("listen ok!\n");

	//优化4:显示客户端的地址
	struct sockaddr_in cin;  //定义客户端地址结构
	socklen_t len;

	//4.等待客户端连接
	while(1){//优化1:允许多个客户端接入
		memset( &cin, 0, sizeof(cin) );
		len = sizeof(sin);

		int connFd = accept(listenFd, (struct sockaddr *)&cin, &len );
		if(connFd < 0){
			perror("accept error");
			exit(1);
		}
		printf("accept (%s:%d) ok!\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port) );

		//5.接受/发送消息
		char buf[BUFSIZ];

		while(1){
			memset( buf, 0, sizeof(buf) );
			ret = recv( connFd, buf, sizeof(buf)-1, 0 );
			if( ret < 0 ){       //出错
				perror( "recv error" );
				continue;
			}
			if( 0 == ret){       //对端关闭套接字
				printf("client closes the socket!\n");
				break;
			}
			//消息处理
			printf("message from client:%s\n", buf);

			//发送消息
			printf("server send message:");
			memset(buf, 0, sizeof(buf));
			if(fgets(buf, sizeof(buf), stdin) == NULL ){
				printf("fgets error\n");
				exit(1);
			}
			send( connFd, buf, strlen(buf), 0 );
		}
		close(connFd);
	}

	//6.关闭套接字
	close(listenFd);

	return 0;
}

2.TCP客户端

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

#define QUIT_STR "quit"

void usage( const char* s ){
	printf("\n %s serv_ip, serv_port" , s);
	printf("\n serv_ip:server ip address");
	printf("\n serv_port:server port (5000 < serv_port < 65536)");
}

int main( int argc, char* argv[] )
{
	//参数检测
	if(argc != 3){
		usage( argv[0] );
		exit(1);
	}
	int port = atoi(argv[2]);
	if(port <= 5000 || port > 65535 ){
		usage( argv[0]);
		exit(1);
	}

	//1.socket 创建流式套接字
	int sockFd = socket(AF_INET, SOCK_STREAM, 0);
	if( sockFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf("socket ok!\n");
	//2.bind(可选)一般不绑定IP地址和端口号,由操作系统自动选定
	//3.connect连接服务器
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );

	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	int ret = connect(sockFd, (struct sockaddr*)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror("connect error");
		exit(1);
	}
	printf("connect ok\n");

	//4.send/recv收发消息
	char buf[BUFSIZ];

	while(1){
		printf("client send message:");
		memset(buf, 0, sizeof(buf));
		if(fgets(buf, sizeof(buf), stdin) == NULL ){
			printf("fgets error\n");
			continue;
		}
		//输入quit,客户端退出
		if( strncmp(buf, QUIT_STR, strlen(QUIT_STR)) == 0 ){
			printf("input quit, client exit!\n");
			break;
		}
		send( sockFd, buf, strlen(buf), 0);
		
		//客户端接受消息
		memset( buf, 0, sizeof(buf) );
		ret = recv( sockFd, buf, sizeof(buf)-1, 0 );
		if( ret < 0 ){       //出错
			perror( "recv error" );
			exit(1);
		}
		if( 0 == ret){       //对端关闭套接字
			printf("server closes the socket!\n");
			break;
		}
		//消息处理
		printf("message from server:%s\n", buf);
	}
	//5.close关闭套接字
	close(sockFd);

	return 0;
}

客户端和服务器实现了:
客户端发消息->服务器收消息->服务器发消息->客户端收消息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单TCP编程 的相关文章

  • 套接字编程Python:如何确保收到完整消息?

    我正在使用 python 3 x 和套接字模块 服务器在 ipv4 地址上运行并使用 tcp 我阅读了一些有关如何发送和接收数据的教程 对于服务器或客户端 要确保发送整个消息 您可以简单地检查发送的数据量是否等于消息的大小 def myse
  • TCP 代理:在后端不可用时保持连接

    在 Docker 设置的上下文中 我想使用类似大使的模式来允许某些容器 例如数据库服务器 正常重新启动 而不必重新启动所有依赖的容器 例如 Web 服务器 并且没有错误消息 因为 数据库服务器不可用 因此 我想知道 是否有一个 TCP 代理
  • Node.js 找不到模块“tcp”

    节点在以下行崩溃 var tcp require tcp 错误文本 node js 201 throw e process nextTick error or error event on first tick Error Cannot f
  • 如何在 MAC OS X 中获得最大 TCP 接收/发送窗口?

    如何在 MAC OS X 中获得最大 TCP 接收 发送窗口 Linux中有两个ctl proc sys net core rmem max 最大 TCP 接收窗口 NET CORE RMEM MAX proc sys net core w
  • TCP 兼容性:为什么 TCP 不兼容数据包广播和组播操作?

    http en wikipedia org wiki User Datagram Protocol http en wikipedia org wiki User Datagram Protocol 与 TCP 不同 UDP 与数据包广播
  • Android TCP 连接最佳实践

    我正在开发一个需要 TCP 连接到 TCP 服务器的 Android 应用程序 用 Node js 编写 我的 Android TCP 客户端正在工作 可以来回发送消息 我的具体问题是 在 Android 中处理与服务器的 TCP 连接的最
  • 是否可以通过 TCP 连接到正在侦听 3G 网络端口的 iPhone?

    我正在开发一个严重依赖 P2P 的应用程序 但我目前没有任何 SIM 卡可供实验 因此我正在 wifi 网络上进行测试 我想知道 3G 网络上的 iPhone 是否可以连接以及是否需要穿越 NAT 设备 您位于提供商的路由器后面 您的 IP
  • 什么是消息边界?

    什么是 消息边界 在以下情况下 TCP 和 UDP 之间的区别之一是 UDP 保留消息 边界 我理解之间的区别TCP and UDP 但我不确定的定义 消息边界 由于 UDP 在每个单独的数据包中包含目的地和端口信息 因此是否可以为消息提供
  • 为什么我们可以将 sockaddr 转换为 sockaddr_in

    我明白为什么强制转换很有用sockaddr to sockaddr in 但我不明白这怎么可能 据我所知 它们的大小相同sockaddr in添加了sin zero使其大小相同 我想知道编译器如何知道从哪里获取信息sockaddr in如果
  • Linux环境下串口数据转换为TCP/IP

    我需要从Linux系统的串口获取数据并将其转换为TCP IP发送到服务器 这很难做到吗 我有一些基本的编程经验 但对 Linux 的经验不多 有没有开源应用程序可以做到这一点 在 Linux 中您不需要编写程序来执行此操作 只是pipe h
  • Python套接字模块:Recv()数据响应被切断

    解释 我目前正在尝试使用 python 脚本控制智能电源板 为了实现这一点 我使用了带有套接字模块的 TCP 连接 大约 75 的情况下 我会得到我正在寻找的响应 数据 并且一切都运行良好 然而 大约 25 的情况下 响应会以完全相同的长度
  • 在 Golang Server 中接受持久的 tcp 连接

    我正在尝试使用 Go 并且想创建一个 TCP 服务器 我可以通过 telnet 访问该服务器 发送命令并接收响应 const CONN HOST localhost CONN PORT 3333 CONN TYPE tcp func mai
  • 两个http请求可以合并在一起吗?如果可以的话,nodeJS服务器如何处理呢?

    昨天我做了一些关于 NodeJS 的演讲 有人问我以下问题 我们知道nodeJS是一个单线程服务器 多个请求是 到达服务器并将所有请求推送到事件循环 如果什么 两个请求同时到达服务器 服务器将如何处理 处理这种情况 我猜到了一个想法并回复如
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • AMQP如何克服直接使用TCP的困难?

    AMQP如何克服直接使用TCP发送消息时的困难 或者更具体地说 在发布 订阅场景中 在 AMQP 中 有一个代理 该代理接收消息 然后完成将消息路由到交换器和队列的困难部分 您还可以设置持久队列 即使客户端断开连接 也可以为客户端保存消息
  • 简单的跨平台 TCP IP API?

    我不打算使用像 QT 或 wxWidgets 的 API 这样的大东西 我只想要可以在 Android iOS Windows Mac Linux 上运行的简单套接字 我正在制作一个事件驱动的纸牌游戏 所以 TCP 是最好的 本质上 我只想
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

    我在过去的两天里阅读了每一篇StackOverflow问题和答案 以及googling当然 关于印地TCP and UDP协议 以便决定在我的用户应用程序和 Windows 服务之间的通信方法中应该使用哪一种 从我目前所看到的来看 UDP是
  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 建立 TCP 连接边界的正确方法

    我的问题是关于如何正确处理使用 tcp 连接接收的数据 事实上 通过建立 tcp 连接 创建了一个流 假设我想发送一条有开头和结尾的消息 由于数据在流中流动而没有指定任何边界 我如何识别消息的开始和结束 我想在消息的开头和结尾处放置一些特殊
  • 将 C++ TCP/IP 应用程序从 IPv4 转换为 IPv6。难的?值得这么麻烦吗?

    多年来 我使用 WinSock 为 Windows 开发了少量 C 服务器 客户端应用程序 路由器 Web 邮件 FTP 服务器等 等等 我开始越来越多地考虑创建这些应用程序的 IPv6 版本 当然 同时也保留原始的 IPv4 版本 问题

随机推荐

  • STL----------C++Primer(笔记)

    1 string string word cin gt gt word getline cin word 关系操作符 lt lt 61 gt gt 61 include lt cctype gt 头文件 string s 61 34 Hel
  • 侯捷-STL与泛型编程(GP)笔记

    1 stl体系结构基础介绍 分配器 xff08 allocator xff09 xff1a 主管分配内存 适配器 xff08 adaptor xff09 xff1a 进行一个转换 xff0c 与另一个对象绑定 include lt iost
  • 课程作业——数据结构与算法C++(1)

    课程作业6 xff08 归并排序 冒泡排序 插入排序 选择排序 xff09 归并排序 冒泡排序 插入排序 选择排序 主程序 include lt iostream gt include lt vector gt using std vect
  • C++程序设计实践指导——第二章 样例讲解

    复数计算器 include lt iostream gt include lt cmath gt include lt string gt include lt fstream gt include lt ctime gt using na
  • 步进电机控制与LCD显示L297与L298

    步进电机控制与LCD显示L297与L298 上次介绍了PWM和L298结合的电机调速 xff01 接下来介绍L297与L298结合的例子 xff01 PWM电机调速 下面是L297的简介 xff1a L297是步进电机专用控制器 xff0c
  • 变分自编码器(一):原来是这么一回事

    https kexue fm archives 5253 过去虽然没有细看 xff0c 但印象里一直觉得变分自编码器 xff08 Variational Auto Encoder xff0c VAE xff09 是个好东西 于是趁着最近看概
  • Linux 安装npm

    1 root 登录linux 2 cd usr loacl node 没有目录就自己创建一个 3 wget https npm taobao org mirrors node v4 4 7 node v4 4 7 linux x64 tar
  • DE1-SOC开发笔记

    verilog FPGA 采用verilog开发语言 xff0c 使用时序和组合逻辑 进行行为 xff0c 数据流 xff0c 结构建模 RTL级编程 xff0c 在实际板卡上面验证逻辑的正确性 sopc xff1a 软硬件结合的开发方式
  • 关于立创EDA使用的几点心得

    对于立创EDA 与AD仅为小白 xff0c 仅布过简单的双层板 xff0c 以下仅记录自己的几点心得 1 如果想要在立创商城 xff0c 嘉立创实现打板贴片一体化 xff0c 采用的普遍的两种方法 xff1a 立创EDA xff0c 有在线
  • 《当下即是生活》季羡林——读书笔记

    目录 书籍简介 经典摘录 三思而行 满招损 xff0c 谦受益 牵就与适应 睁一只眼 闭一只眼 论压力 论恐惧 难得糊涂 春色满寰中 槐花 书籍简介 作者季羡林 本书精选季羡林关于人生活法的散文 xff0c 阐述一个人怎样活在当下 xff0
  • Python装饰器

    Python的装饰器 decorator 可以说是Python的一个神器 xff0c 它可以在不改变一个函数代码和调用方式的情况下给函数添加新的功能 Python的装饰器同时也是Python学习从入门到精通过程中必需要熟练掌握的知识 小编我
  • Python学习笔记--带参数的装饰器

    带参数的装饰器 装饰器的副作用柯里化functools带参数的装饰器多参数小结 装饰器的副作用 def fn 39 39 39 this is fn 39 39 39 help fn 结果 xff1a Help on function fn
  • 六、51单片机之定时器/计数器_理论

    1 什么是定时器 计数器 定时器就是单片机设定一个时间间隔 xff0c 时间间隔到后通知单片机 例如设置100ms的定时器 xff0c 100ms后定时器通知单片机时间到了 1 定时器是单片机的一种内部外设 以前的单片机只有CPU 也就是只
  • 八、51单片机之蜂鸣器

    1 蜂鸣器的原理 蜂鸣器分为有源蜂鸣器和无源蜂鸣器 这里的 源 不是指电源 xff0c 而是指震荡源 1 1 无源蜂鸣器 1 早期蜂鸣器都是无源的 2 内部没有震荡电路 xff0c 无源蜂鸣器比有源蜂鸣器更便宜 3 无源蜂鸣器内部没有震荡源
  • CSS3实现loading效果

    前言 晚上躺床上刷视频的时候看到有个前端大佬写了一个loading xff0c 这是效果 xff1a loading 感觉也挺有意思哈 xff0c 要不自己也写一个 xff0c 学习 43 复习 两不误 但是又因为太晚了 xff0c 不想起
  • C#应用程序界面开发基础——窗体控制(2)——MDI窗体

    MDI窗体 单文档界面 xff08 SDI xff09 多文档界面 xff08 MDI xff09 MDI窗体的概念 MDI窗体 xff08 Multiple Document Interface xff0c 多文档界面 xff09 用于同
  • windows 10 + GTX1650 环境下基于TensorFlow的深度学习环境配置

    因论文需要 xff0c 简单的记录一个深度学习环境的配置过程 说明 xff1a 与广为应用的基于Anaconda的深度学习环境配置方法不同的是 xff0c 本文直接基于Python基础环境 43 Pycharm进行环境的配置 xff0c 不
  • TX2硬盘扩展

    TX2硬盘扩展 硬件平台 xff1a NVIDIA TX2 Samsung SSD 860EVO 系统平台 xff1a Ubuntu 18 04 LTS 安装 将硬盘连接至侧边SATA接口 扩展home 1 查看硬盘所有分区 sudo fd
  • Android手机4G网络设置ipv6

    我的卡是联通的 xff0c 所以下面截图也是联通的 xff0c 移动和电信的卡类似 xff1b 1 进入目录 xff1a 设置 移动网络 接入点名称 xff08 APN xff09 xff1b 2 点击默认的连接项 xff0c 进入详情页
  • 简单TCP编程

    1 TCP服务端 span class token macro property span class token directive hash span span class token directive keyword include