TCP\IP两种实现方式

 

基本:

客户端:

#include"tt.h"

int main()
{
	//1.建立通信套接字
	int fd=socket(AF_INET,SOCK_STREAM,0);
	if(fd==-1)
	{
		perror("fail to socket");
		exit(1);
	}
	//2.连接服务器
	struct sockaddr_in addr;
	bzero(&addr,sizeof(addr));
	addr.sin_family=AF_INET;
	addr.sin_port=htons(6000);//网络字节序的端口号,表示与服务器该端口通信
	inet_pton(AF_INET,my_ip,(void *)&addr.sin_addr.s_addr);//这里的IP地址为服务器的IP地址
	//客户端去连接服务器,不需要知道自己的IP和端口,只需要知道服务器的就行
	int ret=connect(fd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret==-1)
	{
		perror("fail to connect");
		exit(1);
	}
	printf("通信已连接");

	//3.通信
	int num=1;
	int len;
	while(1)
	{
		//发送数据
		char buf[1024];
		sprintf(buf,"你好,服务器,第%d次和你通信",num++);
		send(fd,buf,strlen(buf)+1,0);
		
		//接受数据
		bzero(buf,sizeof(buf));

	len=recv(fd,buf,sizeof(buf),0);
		{
			if(len>0)
			{
				printf("服务器:%s\n",buf);
			}
			else if(len==0)
			{
				printf("和服务器断开");
				break;
			}
			else
			{
				perror("fail to recv");
				break;
			}
		/*	if(!strncasecmp(buf,"quit",strlen("quit")))
			{
				printf("client is exiting!\n");
				exit(1);
			}*/
			sleep(1);

		}
	}

	//4.关闭套接字
	close(fd);
}

服务器:

#include"tt.h"
int main()
{
	//1.创建监听套接字
	int fd=socket(AF_INET,SOCK_STREAM,0);//AF_INET表示ipv4,通信类型tcp为传输流协议即数据报套接字,默认0表示TCP
	if(fd==-1)
	{
		perror("fail to socket");
		exit(1);
	}
	//2.绑定我们本地的IP地址和端口号
	struct sockaddr_in addr;//bend用的结构体
	addr.sin_family=AF_INET;//表示协议族,基于ipv4
	addr.sin_port=htons(6000);//端口号,5000以上就行,由本地小端转为网络传输用的大端,端口号为16位,所以用s
	inet_pton(AF_INET,my_ip,(void *)&addr.sin_addr.s_addr);//将转换后的IP地址放到sin_addr下
	int ret=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
	if(ret==-1)
	{
		perror("fail to bink");
		exit(1);
	}
	//3.设置监听
	ret=listen(fd,128);//同一时刻一次监听多少个,最大值为128,不代表最终只能连接这么多
	//listen的作用是把一个未连接的套接字转换为被动套接字,指示内核应该接受指向该套接字的连接请求。使套接字从close状态转换到listen状态
	if(ret==-1)
	{
		perror("fail to listen");
		exit(1);
	}
	//4.阻塞等待,连接的到达,连接成功后返回通信用的套接字
	struct sockaddr_in caddr;
	int caddrlen=sizeof(caddr);
	int newfd =accept(fd,(struct sockaddr *)&caddr,&caddrlen);//第二个参数用来保存客户端套接字对应的“地方”(包括客户端IP和端口信息等),第三个参数是“地方”的占地大小,返回值对应客户端套接字标识,失败返回-1
	if(newfd==-1)
	{
		perror("fail to accept");
		exit(1);
	}
	//5.开始通行
	char buf[1024];//用来存储接收到的数据

	while(1)
	{
		//读就是receive或read,写就是send或write
		bzero(buf,sizeof(buf));//清0
                               //memset也行
		ret=read(newfd,buf,1024);//(1)通信套接字(2)缓冲区(3)缓冲区长度 --read返回读取的长度,0表示断开连接,负数表示读取失败
		//读:read/recv  写:write/send
		char ip[30]={'0'};
		if(ret>0)
		{
			printf("客户端 %s:%d:%s\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(caddr.sin_port),buf);
			write(newfd,buf,ret);
		}
		else if(ret==0)
		{
			printf("连接已断开\n");
			break;
		}
		else
		{
			perror("fail to read");
			break;
		}
		

	}
	//6.关闭套接字
	close(fd);
	close(newfd);
	return 0;
}

多线程:

#include"tt.h"
#include<pthread.h>
struct pp
	{
		struct sockaddr_in caddr;
		int newfd;
	};

void* TX(void *arg)
{
	char buf[1024];
	struct pp ADD=*(struct pp*)arg;
	while(1)
	{
		bzero(buf,sizeof(buf));//清0
	  int	ret=read(ADD.newfd,buf,1024);//(1)通信套接字(2)缓冲区(3)缓冲区长度 --read返回读取的长度,0表示断开连接,负数表示读取失败
		char ip[30]={'0'};
		if(ret>0)
		{
			printf("客户端 %s:%d:%s\n",inet_ntop(AF_INET,&ADD.caddr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(ADD.caddr.sin_port),buf);
			write(ADD.newfd,buf,ret);
		}
		else if(ret==0)
		{
			printf("连接已断开\n");
			break;
		}
		else
		{
			perror("fail to read");
			break;
		}
	}
	close(ADD.newfd);
	pthread_exit(NULL);
}

int main()
{
	//1.创建监听套接字
	int fd=socket(AF_INET,SOCK_STREAM,0);//AF_INET表示ipv4,通信类型tcp为传输流协议即数据报套接字,默认0表示TCP
	if(fd==-1)
	{
		perror("fail to socket");
		exit(1);
	}
	//2.绑定我们本地的IP地址和端口号
	struct sockaddr_in addr;//bend用的结构体
	addr.sin_family=AF_INET;//表示协议族,基于ipv4
	addr.sin_port=htons(6000);//端口号,5000以上就行,由本地小端转为网络传输用的大端,端口号为16位,所以用s
	inet_pton(AF_INET,my_ip,(void *)&addr.sin_addr.s_addr);//将转换后的IP地址放到sin_addr下
	int ret=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
	if(ret==-1)
	{
		perror("fail to bink");
		exit(1);
	}
	//3.设置监听
	ret=listen(fd,128);//同一时刻一次监听多少个,最大值为128,不代表最终只能连接这么多
	//listen的作用是把一个未连接的套接字转换为被动套接字,指示内核应该接受指向该套接字的连接请求。使套接字从close状态转换到listen状态
	if(ret==-1)
	{
		perror("fail to listen");
		exit(1);
	}
	//4.阻塞等待,连接的到达,连接成功后返回通信用的套接字
	struct sockaddr_in caddr;
	int caddrlen=sizeof(caddr);
	pthread_t pid;
	struct pp ADD;
while(1)
{
	int newfd =accept(fd,(struct sockaddr *)&caddr,&caddrlen);
	if(newfd==-1)
	{
		perror("fail to accept");
		exit(1);
	}
	ADD.caddr=caddr;
	ADD.newfd=newfd;
	pthread_create(&pid,NULL,TX,&ADD);
	pthread_detach(pid);//将线程pid设置为detach状态,就不会产生僵尸线程

}
	//6.关闭套接字
	close(fd);
	return 0;
}

多进程:

#include"tt.h"
#include<signal.h>
int main()
{
	signal(SIGCHLD,SIG_IGN);//忽略子进程退出信号,避免产生僵尸进程
	//1.创建监听套接字
	int fd=socket(AF_INET,SOCK_STREAM,0);//AF_INET表示ipv4,通信类型tcp为传输流协议即数据报套接字,默认0表示TCP
	if(fd==-1)
	{
		perror("fail to socket");
		exit(1);
	}
	//2.绑定我们本地的IP地址和端口号
	struct sockaddr_in addr;//bend用的结构体
	addr.sin_family=AF_INET;//表示协议族,基于ipv4
	addr.sin_port=htons(6000);//端口号,5000以上就行,由本地小端转为网络传输用的大端,端口号为16位,所以用s
	inet_pton(AF_INET,my_ip,(void *)&addr.sin_addr.s_addr);//将转换后的IP地址放到sin_addr下
	int ret=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
	if(ret==-1)
	{
		perror("fail to bink");
		exit(1);
	}
	//3.设置监听
	ret=listen(fd,128);//同一时刻一次监听多少个,最大值为128,不代表最终只能连接这么多
	//listen的作用是把一个未连接的套接字转换为被动套接字,指示内核应该接受指向该套接字的连接请求。使套接字从close状态转换到listen状态
	if(ret==-1)
	{
		perror("fail to listen");
		exit(1);
	}
	//4.阻塞等待,连接的到达,连接成功后返回通信用的套接字
	struct sockaddr_in caddr;
	int caddrlen=sizeof(caddr);
	while(1)
{
	int newfd =accept(fd,(struct sockaddr *)&caddr,&caddrlen);
	if(newfd==-1)
	{
		perror("fail to accept");
		exit(1);
	}
	pid_t pid=fork();
	if(pid<0)
	{
		perror("fail to fork");
		exit(1);
	}
	if(pid==0)
	{
	char buf[1024];
	while(1)
	{
		bzero(buf,sizeof(buf));
		ret=read(newfd,buf,1024);//(1)通信套接字(2)缓冲区(3)缓冲区长度 --read返回读取的长度,0表示断开连接,负数表示读取失败
		//读:read/recv  写:write/send
		char ip[30]={0};
		if(ret>0)
		{
			printf("客户端 %s:%d:%s\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(caddr.sin_port),buf);
			write(newfd,buf,ret);
		}
		else if(ret==0)
		{
			printf("连接已断开\n");
			break;
		}
		else
		{
			perror("fail to read");
			break;
		}	
	}
	close(newfd);

  }

}
		//6.关闭套接字
	close(fd);
		return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值