当前位置: 首页 > news >正文

c语言学习5==TCP和socket

socket实现不同服务器上的进程间的通信。

socket是一个伪文件,分成两个部分:读缓冲区和写缓冲区。所以socket一旦建立就会在PCB中对应生成一个文件描述符fd。

 

 socket必须成对出现。

=============================

网络字节序:

大小端:小端,低位存低地址,高位存高地址。大端相反。

总之在网络间传递的包都是大端。

 网络字节序和主机字节序的转换

点分十进制转网络大端

#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
//准备转换成大端的IP地址
	char buf[]="192.168.136.101";
	unsigned int num=0;
//转成大端
	inet_pton(AF_INET,buf,&num);
	unsigned char * p=(unsigned char *)&num;
	printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));
//大端转小端
	char ip[16]="";
	printf("%s\n",inet_ntop(AF_INET,&num,ip,16));
	return 0;
}

IPV4套接字结构体

 我们需要指定的就是协议 IP 端口,将这三个东西封装成一个结构体

man 7 ip

IPV4套接字结构体       

   struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET 协议 */
               in_port_t      sin_port;   /* port in network byte order 端口*/
               struct in_addr sin_addr;   /* internet address IP地址*/
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };
 

通用套接字结构体

TCP特点:出错重传,每次发送数据对方都会回ACK,可靠。

socket服务器编写


#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
	//创建套接字/文件描述符
	int lfd = socket(AF_INET,SOCK_STREAM,0);
	//绑定。将协议和端口转成大端封装进结构体
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8000);
	//	addr.sin_addr.s_addr = INADDR_ANY;//绑定的是通配地址
	//此处将文件描述符绑定到本服务器的IP地址
	inet_pton(AF_INET,"192.168.136.101",&addr.sin_addr.s_addr);
	int ret = bind(lfd,(struct sockaddr *)&addr,sizeof(addr));
	if(ret < 0)
	{
		perror("");
		exit(0);

	}
	//监听
	listen(lfd,128);
	//提取
	struct sockaddr_in cliaddr;
	socklen_t len = sizeof(cliaddr);
	int cfd = accept(lfd,(struct sockaddr *)&cliaddr,&len);
	char ip[16]="";
	printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,
				ip,16),	ntohs(cliaddr.sin_port));
	//读写
	char buf[1024]="";
	while(1)
	{
		bzero(buf,sizeof(buf));
	//	int n = read(STDIN_FILENO,buf,sizeof(buf));
	//	write(cfd,buf,n);
		int n =0;
		n = read(cfd,buf,sizeof(buf));
		if(n ==0 )//如果read返回等于0,代表对方关闭 
		{
			printf("client close\n");
			break;
		}
		printf("%s\n",buf);
	
	}
	//关闭
	close(lfd);
	close(cfd);
	return 0;
}


三次握手

多进程实现并发服务器

与线程版进行对比

 gcc 02_process_tcp_server.c wrap.c


#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "wrap.h"
void free_process(int sig)
{
	pid_t pid;
	while(1)
	{
		pid = waitpid(-1,NULL,WNOHANG);
		if(pid <=0 )//小于0 子进程全部退出了 =0没有进程没有退出
		{
			break;
		}
		else
		{
			printf("child pid =%d\n",pid);
		}
	}



}
int main(int argc, char *argv[])
{
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set,SIGCHLD);
	sigprocmask(SIG_BLOCK,&set,NULL);
	//创建套接字,绑定
	int lfd = tcp4bind(8008,NULL);
	//监
	Listen(lfd,128);
	//提取
	//回射
	struct sockaddr_in cliaddr;
	socklen_t len = sizeof(cliaddr);
	while(1)
	{
		char ip[16]="";
		//提取连接,
		int cfd = Accept(lfd,(struct sockaddr *)&cliaddr,&len);
		printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
				ntohs(cliaddr.sin_port));
		//fork创建子进程
		pid_t pid;
		pid = fork();
		if(pid < 0)
		{
			perror("");
			exit(0);
		}
		else if(pid == 0)//子进程
		{
			//关闭lfd
			close(lfd);
			while(1)
			{
			char buf[1024]="";

			int n = read(cfd,buf,sizeof(buf));
			if(n < 0)
			{
				perror("");
				close(cfd);
				exit(0);
			}
			else if(n == 0)//对方关闭j
			{
				printf("client close\n");
				close(cfd);
				exit(0);
			
			}
			else
			{
				printf("%s\n",buf);
				write(cfd,buf,n);
			//	exit(0);	
			}
			}
		
		}
		else//父进程
		{
			close(cfd);
			//回收
			//注册信号回调
			struct sigaction act;
			act.sa_flags =0;
			act.sa_handler = free_process;
			sigemptyset(&act.sa_mask);
			sigaction(SIGCHLD,&act,NULL);
			sigprocmask(SIG_UNBLOCK,&set,NULL);
		
		}
	}
	//关闭



	return 0;
}


1

2

3

线程版服务器

#include <stdio.h>
#include <pthread.h>
#include "wrap.h"

typedef struct c_info
{
	int cfd;
	struct sockaddr_in cliaddr;
}CINFO;
void* client_fun(void *arg);
int main(int argc, char *argv[]){
	if(argc<2)
	{
		printf("argc<2 >>>> \n ./a.out 8000 \n");
		return 0;
	}
	short port=atoi(argv[1]);
	int lfd=tcp4bind(port,NULL);
	Listen(lfd,128);
	struct sockaddr_in cliaddr;
	socklen_t len=sizeof(cliaddr);
	CINFO *info;
	while(1){
		int cfd=Accept(lfd,(struct sockaddr *)&cliaddr,&len);
		char ip[16]="";
		printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
				ntohs(cliaddr.sin_port)
		      );
		pthread_t pthid;
		info=malloc(sizeof(CINFO));
		info->cfd=cfd;
		info->cliaddr=cliaddr;
	
		pthread_create(&pthid,NULL,client_fun,info);
	}
	return 0;


}

void* client_fun(void *arg)
{
	CINFO *info=(CINFO *)arg;
	char ip[16]="";

	printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16),
			ntohs(info->cliaddr.sin_port));
	while(1)
	{
		char buf[1024]="";
		int count=0;
		count =read(info->cfd,buf,sizeof(buf));
		if(count<0)
		{
			printf("client close\n");
			break;	
		}
		else if (count==0)
		{
			printf("clent close\n");
			break;
		}
		else
		{
			printf("%s\n",buf);
			write(info->cfd,buf,count);
		}
	}
	close(info->cfd);
	free(info);
}

相关文章:

  • 【web-渗透测试方法】(15.5)测试访问控件
  • Linux 基础指令
  • C++语言基础Day3-内联函数
  • 78-Java的可变参数、集合操作的工具类-Collections
  • Ruby on Rails 实践课程:创建 aloe 项目
  • 【构建并发程序】3-原子变量
  • Java学习任务总结【14】
  • Linux安装JDK最新版
  • 3.7背景色半透明
  • Android 12 进程native crash流程分析
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • python+vue+elementui高校学生成绩补考通知系统django
  • 代码坏味道与重构之霰弹式修改和依恋情结
  • 【web-渗透测试方法】(15.6)测试基于输入的漏洞
  • Java高频面试题【基础篇】
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • CSS 提示工具(Tooltip)
  • jquery ajax学习笔记
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • JS专题之继承
  • k8s 面向应用开发者的基础命令
  • MySQL-事务管理(基础)
  • python学习笔记 - ThreadLocal
  • Python学习之路13-记分
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • SQLServer之创建显式事务
  • 马上搞懂 GeoJSON
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​卜东波研究员:高观点下的少儿计算思维
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (145)光线追踪距离场柔和阴影
  • (9)STL算法之逆转旋转
  • (C语言)fgets与fputs函数详解
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (一)Linux+Windows下安装ffmpeg
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .Net Memory Profiler的使用举例
  • .net Stream篇(六)
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET开发者必备的11款免费工具
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [ CTF ]【天格】战队WriteUp- 2022年第三届“网鼎杯”网络安全大赛(青龙组)
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • [ai笔记3] ai春晚观后感-谈谈ai与艺术
  • [Android] 修改设备访问权限
  • [ARC066F]Contest with Drinks Hard
  • [C puzzle book] types