多路复用并发服务器实现服务器与所有客户端双向通信

//客户端 client.c
/*
多路复用并发服务器实现服务器与所有客户端双向通信
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>     
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
	if(argc != 3){
		printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
		exit(1);
	}
	int soc_fd = socket(AF_INET,SOCK_STREAM,0);
	if(soc_fd < 0){
		perror("socket error");
		exit(1);
	}
	int on =1;
	setsockopt(soc_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));	
	/*struct sockaddr_in client_addr;//客户端绑定客户端信息,服务器绑定服务器信息
	client_addr.sin_family = AF_INET;
	client_addr.sin_port = htons(6666);
	client_addr.sin_addr.s_addr = inet_addr("192.168.90.74");
	
	int ret_bind = bind(soc_fd,(struct sockaddr *)&client_addr,sizeof(client_addr));
	if(ret_bind<0){
		perror("bind error");
		exit(1);
	}*/
	struct sockaddr_in server_addr;//绑定服务器信息
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);		
	int ret_connect = connect(soc_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(ret_connect<0){
		perror("connect error");
		exit(1);
	}	
	fd_set myset;	
	char buf[20];
	int ret_recv;
	while(1){
		FD_ZERO(&myset);
		FD_SET(0,&myset);
		FD_SET(soc_fd,&myset);
		select(soc_fd+1,&myset,NULL,NULL,NULL);
		if(FD_ISSET(0,&myset)){
			bzero(buf,sizeof(buf));
			gets(buf);
			send(soc_fd,buf,strlen(buf),0);			
		}
		if(FD_ISSET(soc_fd,&myset)){
			bzero(buf,sizeof(buf));
			ret_recv = recv(soc_fd,buf,sizeof(buf),0);
			if(ret_recv==0){
				close(soc_fd);
				break;
			}
			printf("%s\n",buf);			
		}
	}	
	return 0;
}
//服务器 server.c
#include "link.h"
int main(int argc,char *argv[])
{
	if(argc!=3){
		perror("argc error");
		exit(1);
	}
	char ch[100] = {};//接收缓冲区
	char buf[100] = {};//发送缓冲区
	int send_fd;//服务器发送的客户端文件描述符
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);//ipv4协议,流式套接字
	if(socket_fd==-1){//创建流式套接字失败
		perror("socket error");
		exit(1);
	}
	
	int on=1;//端口可以重复使用
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;//iPv4
	server_addr.sin_port = htons(atoi(argv[2]));//服务器端口号
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);//服务器IP地址
	int bind_ret = bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(bind_ret==-1){
		perror("bind error");
		exit(1);
	}
	listen(socket_fd,5);//监听套接字
	plink Describe_Link;//套接字文件描述符链表
	plink temp_link;
	int temp_fd;
	fd_set recv_set;//创建集合
	int accept_ret;//连接后的文件描述符
	int Max_nfds = socket_fd;//起始最大文件描述符值
	int ret;
	Init_Link(&Describe_Link);//初始化文件描述符链表
	while(1){
		FD_ZERO(&recv_set);//清空集合
		FD_SET(0,&recv_set);//添加0文件描述符
		FD_SET(socket_fd,&recv_set);//添加socket_fd文件描述符
		display(Describe_Link,&recv_set);//遍历链表,添加所有文件描述符
		select(Max_nfds+1,&recv_set,NULL,NULL,NULL);//阻塞等待
		if(FD_ISSET(socket_fd,&recv_set)){//有客户端请求连接
			accept_ret = accept(socket_fd,NULL,NULL);//获取新的套接字文件描述符
			printf("客户端%d已连接......\n",accept_ret);
			Insert_Link_Head(Describe_Link,accept_ret);//头插到链表中
			Max_nfds = Find_Link_Node(Describe_Link,0);//更新新的最大文件描述符
			//printf("Max_nfds = %d\n",Max_nfds);
		}
		if(FD_ISSET(0,&recv_set)){
			bzero(buf,sizeof(buf));//清空缓冲区
			bzero(ch,sizeof(ch));
			gets(ch);//输入请按这个格式输入4:hello 客户端名字:内容
			sscanf(ch,"%d:%s",&send_fd,buf);//指定客户端发送数据
			send(send_fd,buf,strlen(buf),0);
		}
		temp_link = Describe_Link->next;
		while(temp_link != Describe_Link){//遍历链表,监测所有套接字文件描述符
			if(FD_ISSET(temp_link->data,&recv_set)){
				bzero(ch,sizeof(ch));
				ret = recv(temp_link->data,ch,sizeof(ch),0);
				if(ret == 0){
					temp_fd = temp_link->data;//保存套接字文件描述符
					Del_Link_Data(Describe_Link,temp_link->data);//删除该套接字文件
					//display_value(Describe_Link);
					printf("客户端%d已断开连接......\n",temp_fd);
					close(temp_fd);//关闭客户端对应的文件描述符,释放资源,下次再有客户端连接可以使用该文件描述符
					break;
				}
				printf("客户端%d发送的消息为:%s\n",temp_link->data,ch);
			}
			temp_link = temp_link->next;
		}
	}
	return 0;
}
//link.c
#include "link.h"
/*
头指针初始化
*/
void Init_Link(plink *P_Link)
{
	*P_Link = (plink)malloc(sizeof(link));
	if(*P_Link==NULL){
		printf("*P_Link malloc error %s\n",__FUNCTION__);
		return;
	}
	(*P_Link)->next = *P_Link;
}
/*
创建新节点
*/
plink Creat_Node(datatype d)
{
	plink P_Link = (plink)malloc(sizeof(link));
	if(P_Link==NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
		return;
	}
	P_Link->data = d;
	P_Link->next = P_Link;
	return P_Link;
}
/*
头插法,添加在第一个元素前面
*/
void Insert_Link_Head(plink head,datatype data)
{
	if(head == NULL){
		return ;
	}
	plink node = Creat_Node(data);
	if(node == NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
	}
	node->next = head->next;
	head->next = node;
}
/*
尾插法,添加在最后一个元素后面
*/
void Insert_Link_Tail(plink head,datatype data)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p->next != head){
		p = p->next;
	}
	plink node = Creat_Node(data);
	if(node == NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
	}
	node->next = p->next;
	p->next = node;
}
/*
删除一个节点
*/
void Del_Link_Data(plink head,datatype data)
{
	if(head==NULL){
		return;
	}
	plink p = head;
	plink old_node;
	while(p->next!=head){
		if(p->next->data == data){
			old_node=p->next;
			p->next = p->next->next;
			old_node->next = NULL;
			free(old_node);
			continue;
		}
		p = p->next;
	}
}
/*
修改一个节点
*/
void Updata_Link(plink head,datatype Old_data,datatype New_data)
{
	if(head==NULL){
		return;
	}
	plink p = head;
	plink old_node;
	while(p->next!=head){
		if(p->next->data == Old_data){
			old_node=p->next;
			plink New_node=Creat_Node(New_data);
			if(New_node == NULL){
				return;
			}
			New_node->next=p->next->next;
			p->next = New_node;
			old_node->next = NULL;
			free(old_node);
			continue;
		}
		p = p->next;
	}
}
/*
	查询
*/
datatype Find_Link_Node(plink head,datatype data)
{
	if(head==NULL){
		return;
	}
	
	plink p = head->next;
	while(p!=head){
		if(p->data > data){
			data = p->data;
		}
		p = p->next;
	}
	return data;
}
/*
遍历
*/
void display(plink head,fd_set *recv_set)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p!=head){
		FD_SET(p->data,recv_set);//添加每一个文件描述符到集合中
		p = p->next;
	}
}
/*
遍历链表中的值
*/
void display_value(plink head)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p!=head){
		printf("%d\n",p->data);
		p = p->next;
	}
}
//link.h
#ifndef __LINK___
#define __LINK___
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

typedef int datatype;
typedef struct linklist{
	datatype data;//数据域
	struct linklist *next;//指向下一个节点
}link,*plink;

extern void Init_Link(plink *P_Link);
extern void Insert_Link_Head(plink head,datatype data);
extern void display(plink head,fd_set *recv_set);
extern void Insert_Link_Tail(plink head,datatype data);
extern void Del_Link_Data(plink head,datatype data);
extern void Updata_Link(plink head,datatype Old_data,datatype New_data);
extern datatype Find_Link_Node(plink head,datatype data);
extern void display_value(plink head);
#endif
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值