套接字编程:基于TCP协议的通信编程(优化)

套接字编程:基于TCP协议的通信编程(优化)

问题解决

  • 解决了上篇代码中每个客户端只能和服务器通信一次的问题

解决措施

  1. 通过fork()创建子进程来解决这个问题,每当服务器与一个客户端新建一个连接后,这时就为其创建一个子进程。
  2. 然后让子进程再来处理用新套接字newfd进行数据收发的工作,然后在处理完这个客户端与服务器的通信任务后,再自动退出。
  3. 而父进程则只负责用最开始生成的套接字sockfd来监听,并为新的连接生成套接字newfd。
  4. 最后每当有一个子进程退出的时候用通过回调函数signal(SIGCHLD,sigcb),处理掉系统中的僵尸子进程

tcp_process.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>//地址结构
#include<arpa/inet.h>//字节序转换接口
#include<sys/socket.h>//套接字接口
#include<sys/wait.h>



#define MAX_LISTEN_NUM 5


void sigcb(int no)//处理掉僵尸进程
{
	while(waitpid(-1,NULL,WNOHANG)>0);
}

int main()
{
	signal(SIGCHLD,sigcb);
	//1.创建套接字
	int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(sockfd<0){
		perror("socket error");
		return -1;
	}
	//2.绑定地址信息
	struct sockaddr_in addr;
	addr.sin_family=AF_INET;
	addr.sin_port=htons(9000);
	addr.sin_addr.s_addr=inet_addr("0.0.0.0");
	socklen_t len=sizeof(addr);
	int ret = bind(sockfd,(struct sockaddr*)&addr,len);
	if(ret<0){
		perror("bind error");
		return -1;
	}
	//3.开始监听
	ret =listen(sockfd,MAX_LISTEN_NUM);
	if(ret<0){
		perror("listen error");
		return -1;
	}
	//4.获取新连接
	while(1){
		struct sockaddr_in cliaddr;
		int newfd=accept(sockfd,(struct sockaddr*)&cliaddr,&len);
		if(newfd<0){
			perror("accept error");
			continue;
		}	
		if(fork()==0){//表示子进程
			while(1){
				//5.使用新连接与客户端通信(收发数据)
				char buf[1024]={0};
				//接收数据
				ret=recv(newfd,buf,1023,0);
				if(ret<0){
					perror("recv error");
					close(newfd);
					return -1;
				}else if(ret==0){//返回值为0,表示该客户端已断开连接
					printf("peer shutdown\n");
					close(newfd);
					return -1;
				}	
				printf("%s:%d say:%s\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port),buf);
				//发送数据
				memset(buf,0x00,1024);
				printf("server say:");
				fflush(stdout);
				scanf("%s",buf);
				ret=send(newfd,buf,strlen(buf),0);	
			}
			exit(0);
		}
		close(newfd);
	}
	//6.关闭套接字
	close(sockfd);
	return 0;
}

tcp_client.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<netinet/in.h>//地址结构
#include<arpa/inet.h>//字节序转换接口
#include<sys/socket.h>//套接字接口

int main()
{
	//1.创建套接字
	int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(sockfd<0){
		perror("socket error");
		return -1;
	}
	//2.绑定地址信息(不推荐)
	//3.向服务端发起连接请求
	struct sockaddr_in srv_addr;
	srv_addr.sin_family=AF_INET;
	srv_addr.sin_port=htons(9000);
	srv_addr.sin_addr.s_addr=inet_addr("192.168.204.144");
	socklen_t len=sizeof(srv_addr);
	int ret=connect(sockfd,(struct sockaddr*)&srv_addr,len);
	if(ret<0){
		perror("connect error");
		return -1;
	}
	//4.收发数据
	while(1){
		//发送数据
		printf("client say:");
		fflush(stdout);
		char buf[1024]={0};
		scanf("%s",buf);
		ret=send(sockfd,buf,strlen(buf),0);
		if(ret<0){
			perror("send error");
			return -1;
		}	
		//接收数据	
		memset(buf,0x00,1024);
		ret=recv(sockfd,buf,1023,0);
		if(ret<0){
			perror("recv errror");
			return -1;
		}else if (ret==0){
			printf("peer shutdown");
			return -1;
		}
		printf("server say:%s\n",buf);
	}
	
	//5.关闭套接字
	close(sockfd);
	return 0;
}

通信演示
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值