【linux网络编程学习笔记】第二节:创建TCP通信(双向)(socket、bind、listen、accept、connect、recv、send、shutdown、server\client)

2023-05-16

Work won't kill but worry will.

  劳动无害,忧愁伤身。

上一篇章中创建了TCP的客户端的服务器,但是只能单向发送,本章节主要讲解如何进行双向互发消息,实现的过程很简单,看过上一阶段的章节就不难发现可以使用线程可,进行一遍发送一遍接收。

     废话不多说直接上例程

TCP相关API说明点击跳转

线程相关说明点击跳转

tcp_server.c 服务端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>


void *send_thread(void *arg)
{
	int client_fd = *(int *)arg;
	char buffer[1024];
	ssize_t send_size;

	while(1)
	{
		bzero(buffer, sizeof(buffer));
		scanf("%s",buffer);
		/*
			接受来自与客户端的数据,这个接受具备阻塞特性
			跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
		*/
		send_size = send(client_fd, buffer, strlen(buffer), 0);
		if(send_size == -1)
		{
			perror("发送数据异常");
			break;
		}
	}


	return NULL;
}

int main(void)
{
	char buffer[1024];
	int skt_fd;
	int client_fd;
	int retval;
	ssize_t recv_size;
	/*
		获取程序通信的套接字(接口)
		AF_INET:IPV4的协议
		SOCK_STREAM:指定TCP协议
		0:代表不变化协议内部(ip手册中指定的参数)
	*/
	skt_fd = socket( AF_INET, SOCK_STREAM, 0);
	if(skt_fd == -1)
	{
		perror("申请套接字失败");
		return -1;
	}

	//绑定自己的地址信息
	struct sockaddr_in native_addr;
	//指定引用IPV4的协议
	native_addr.sin_family = AF_INET;
	//指定端口号,转化为网络字节序(大端序)
	native_addr.sin_port = htons(6666);
	//将所有的IP地址转化为二进制的网络字节序的数据进行绑定
	native_addr.sin_addr.s_addr = htonl(INADDR_ANY);


	/*
		将指定的地址信息及本程序的套接字绑定在一起
		skt_fd:套接字的文件描述符
		&native_addr:需要绑定的地址信息结构体(每个协议的地址信息结构体是不一样的,
		我们用IPV4的协议便需要引用struct sockaddr_in)
		sizeof(native_addr):传入的结构体长度
	*/
	retval = bind( skt_fd, (struct sockaddr *)&native_addr, sizeof(native_addr));
	if(retval == -1)
	{
		perror("绑定套接字地址失败");
		close(skt_fd);
		return -1;
	}


	/*
		设置套接字的同时通信最大连接数为50,并且将这个套接字的属性设置为可监听属性
	*/
	retval = listen(skt_fd, 50);
	if(retval == -1)
	{
		perror("设置最大连接数失败");
		close(skt_fd);
		return -1;
	}

	//用于接收客户端的地址信息
	struct sockaddr_in client_addr;
	socklen_t sklen = sizeof(client_addr);

	/*
		等待客户端链接,链接成功后返回一个代表客户端通信的文件描述符,具备阻塞特性
		skt_fd:代表套接字接口
		client_addr:链接成功后客户端的地址信息会存放到这里面
		sklen:代表结构体的长度
	*/
	client_fd = accept(skt_fd, (struct sockaddr *)&client_addr, &sklen);
	if(client_fd == -1)
	{
		perror("客户端链接失败");
		close(skt_fd);
		return -1;
	}

	printf("服务器:客户端连接成功\n");
	printf("客户端信息:\n客户端IP为%s,端口号为%hu\n",
	 	inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

	//创建发送的子线程
	pthread_t tid;
	pthread_create(&tid, NULL, send_thread, &client_fd);

	while(1)
	{
		bzero(buffer,sizeof(buffer));
		/*
			接受来自与客户端的数据,这个接受具备阻塞特性
			跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
		*/
		recv_size = recv(client_fd,buffer,sizeof(buffer),0);
		if(recv_size == -1)
		{
			perror("接受数据异常");
			close(skt_fd);
			close(client_fd);
			return -1;
		}else if(recv_size == 0)//代表客户端断开连接
			break;
			
		printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, buffer);
	}


	close(client_fd);//关闭客户端通信
	close(skt_fd);//关闭服务器的socket资源

	return 0;
}

tcp_client.c 客户端

#include <stdio.h>
#include <sys/types.h>   
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>


void *recv_data(void *arg)
{
	int skt_fd = *(int *)arg;
	char buffer[1024];
	ssize_t recv_size;

	while(1)
	{
		bzero(buffer, sizeof(buffer));

		/*
			接受来自与客户端的数据,这个接受具备阻塞特性
			跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
		*/
		recv_size = recv(skt_fd, buffer, sizeof(buffer), 0);
		if(recv_size == -1)
		{
			perror("接受数据异常");
			break;
		}
		else if(recv_size == 0)//代表服务器断开连接
		{
			close(skt_fd);
			return 0;
		}
		printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, buffer);
	
	}

	return NULL;

}


//./client 192.168.33.3
int main(int argc, const char *argv[])
{
	char buffer[1024];
	int skt_fd;
	int retval;
	ssize_t send_size;

	/*
		获取程序通信的套接字(接口)
		AF_INET:IPV4的协议
		SOCK_STREAM:指定TCP协议
		0:代表不变化协议内部(ip手册中指定的参数)
	*/
	skt_fd = socket( AF_INET, SOCK_STREAM, 0);
	if(skt_fd == -1)
	{
		perror("申请套接字失败");
		return -1;
	}

	//服务器的地址信息
	struct sockaddr_in srv_addr;
	//指定引用IPV4的协议
	srv_addr.sin_family = AF_INET;
	//指定端口号,转化为网络字节序(大端序)
	srv_addr.sin_port = htons(6666);
	//将所有的IP地址转化为二进制的网络字节序的数据进行绑定	
	srv_addr.sin_addr.s_addr = inet_addr("192.168.32.68");

	retval = connect(skt_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
	if(retval == -1)
	{
		perror("客户端连接到服务器失败\n");
		close(skt_fd);
		return -1;
	}

	printf("客户端:连接服务器成功\n");

	//创建接收的子线程
	pthread_t tid;
	pthread_create(&tid, NULL, recv_data, &skt_fd);

	while(1)
	{
		scanf("%s", buffer);

		send_size = send( skt_fd, buffer, strlen(buffer), 0);
		if(send_size == -1)
			break;
	}


	close(skt_fd);

	return 0;
}

 

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

【linux网络编程学习笔记】第二节:创建TCP通信(双向)(socket、bind、listen、accept、connect、recv、send、shutdown、server\client) 的相关文章

随机推荐

  • hexo next 博客,jsdelivr cdn报错无法访问

    一 博客环境 我的hexo版本是5 4 0 xff0c next版本是7 8 0 因 jsdelivr cdn报错导致博客首页无法访问 二 修改next cdn 首先进入hexo博客首页 xff0c F12查看报错的 jsdelivr 地址
  • busuanzi.ibruce.info 有时候报502,怎么解决

    一 现象 https busuanzi ibruce info 访问经常出现502 导致个人博客的访问人数无法正常显示 二 如何解决 用chrome 打开busuanzi ibruce info xff0c 点url链接前的那个锁 然后看到
  • BigDecimal和Double的区别

    Double span class token number 0 3 span span class token number 0 2 span span class token operator 61 span span class to
  • 对科里奥利力的理解

    首先创造一个情景 xff0c 方便理解 假设你站在一个这样的封闭靶场 xff08 全封闭 xff09 上 xff0c 这个靶场在以大小为 的角速度做匀速圆周运动 xff08 速度不大不小 xff0c 你感觉不到 xff0c 而且靶场没风 x
  • typora使用技巧

    1 Typora vue theme的介绍与下载 typora vue theme是参考了Vue文档风格而开发的一个 Typora 自定义主题 点击此处下载 2 如何安装 a 下载本主题中的vue css vue dark css文档和包含
  • 序列化什么意思

    序列化就是一种用来处理对象流的机制 xff0c 将对象转化成字节序列后可以保存在磁盘上 xff0c 或通过网络传输 xff0c 以达到以后恢复成原来的对象
  • mybatis plus 事务回滚总结

    https www cnblogs com c2g5201314 p 13163097 html
  • throw 和 try catch 的区别

    try catch是直接处理 xff0c 处理完成之后程序继续往下执行 xff0c throw则是将异常抛给它的上一级处理 xff0c 程序便不往下执行了
  • throw的异常日志会打印吗

    throw 就是要把异常继续抛出 xff0c 要么由上层方法解决 xff0c 要么会终止程序运行
  • java assert什么意思

    assert 意为断言的意思 xff0c 这个关键字可以判断布尔值的结果是否和预期的一样 xff0c 如果一样就正常执行 xff0c 否则会抛出AssertionError assert 的使用 xff1a span class token
  • throw和throws的区别

    throws xff1a 用来声明一个方法可能产生的所有异常 xff0c 不做任何处理而是将异常往上传 xff0c 谁调用我我就抛给谁 用在方法声明后面 xff0c 跟的是异常类名 可以跟多个异常类名 xff0c 用逗号隔开 表示抛出异常
  • 1024有感

    2022 10 24 1024节日快乐 xff01 好好学习 xff0c 天天向上 x1f600
  • 互联网项目一般几轮测试

    第一轮测试 xff1a 要覆盖所有测试用例 所有功能都要跑一遍 第二轮测试 xff1a 重点功能的测试 还要把第一轮测试发现的问题 xff0c 根据开发修改完成的结果 xff0c 进行验证 最后一轮是回归测试 xff1a 验证所有bug是否
  • IDEA pom文件 ctrl alt l无法格式化

    File gt Manage IDE settings gt Restore Default settings 恢复IDEA默认设置后 xff0c 即可格式化pom文件
  • 科里奥利力简单清晰的推导

    看到一个比较好的科里奥利力推导方法 xff1a 如果你不太理解科里奥利力 xff0c 可以看一下我的这篇文章 xff1a 对科里奥利力的理解 本文参考 xff1a 1 黄永义 科里奥利力简单而清晰的导出 J 广西物理 2015 36 04
  • java实体类命名

    Entity xff1a 与数据库表结构一一对应 xff0c 通过Dao层向上传输数据源对象 Dto xff08 Data Transfer Object xff09 xff1a 数据传输对象 xff0c Service或Manager向外
  • 字节的高低位互换

    蝶式交换法 unsigned char Reverse byte unsigned char data data 61 data lt lt 4 data gt gt 4 data 61 data lt lt 2 amp 0xcc data
  • 没有Build文件夹的情况下(最新的vue-cli3没有)怎么关闭掉ESlink

    这里写目录标题 一般的注释掉Build中的方法最新的vue cli3没有build文件夹怎么办 一般的注释掉Build中的方法 在build文件夹 gt webpack base conf js中注释以下代码 和在IntelliJ IDEA
  • 使用zed摄像头跑ORB_SLAM2

    zed ros wrapper安装 首先对zed ros wrapper安装 xff1a 具体操作步骤及代码的参考链接 xff1a https github com stereolabs zed ros wrapper git mkdir
  • 【linux网络编程学习笔记】第二节:创建TCP通信(双向)(socket、bind、listen、accept、connect、recv、send、shutdown、server\client)

    Work won 39 t kill but worry will 劳动无害 xff0c 忧愁伤身 上一篇章中创建了TCP的客户端的服务器 xff0c 但是只能单向发送 xff0c 本章节主要讲解如何进行双向互发消息 xff0c 实现的过程