8.19作业

1.项目:建立服务器和客户端(客户端发出的信息其他客户端接收,服务器发出的信息全部客户端接收)

服务器代码:

cs 复制代码
#include <25061head.h>

#define SER_IP "192.168.109.126"
#define SER_PORT 8888

typedef struct Node
{
	union
	{
		int data;
		int len;
	};
	char username[50];
	struct sockaddr_in addr;
	struct Node *next;
}*linklist;

linklist creat_head()
{
	linklist head=(linklist)malloc(sizeof(struct Node));
	if(head==NULL)
	{
		return NULL;
	}
	head->len=0;
	head->next=NULL;
	return head;
}

linklist creat_node(int fd,const char* name,struct sockaddr_in addr)
{
	linklist s=(linklist)malloc(sizeof(struct Node));
	if(NULL==s)
	{
		return NULL;
	}

	s->data=fd;
	strncpy(s->username,name,sizeof(s->username)-1);
	s->username[sizeof(s->username)-1]='\0';
	s->next=NULL;
	return s;
}

int insert_rear(int fd,const char* name,struct sockaddr_in addr,linklist head)
{
	if(NULL==head)
	{
		return -1;
	}
	linklist s=creat_node(fd,name,addr);
	if(NULL==s)
	{
		return -1;
	}
	linklist p=head;
	while(p->next!=NULL)
	{
		p=p->next;
	}
	p->next=s;
	head->len++;
	return 0;
}

int delete_client(linklist head,int fd)
{
	if(NULL==head||NULL==head->next)
	{
		return -1;
	}
	linklist prev=head;
	linklist curr=head->next;
	while(curr!=NULL)
	{
		if(curr->data==fd)
		{
			prev->next=curr->next;
			free(curr);
			head->len--;
			return 0;
		}
		prev=curr;
		curr=curr->next;
	}
	return -1;
}

const char *find_username(linklist head,int fd)
{
	linklist p=head->next;
	while(p!=NULL)
	{
		if(p->data==fd)
		{
			return p->username;
		}
		p=p->next;
	}
	return "unknown";
}

void broadcast(linklist head,char *msg,int exclude_fd)
{
	linklist p=head->next;
	while(p!=NULL)
	{
		if(p->data!=exclude_fd)
		{
			send(p->data,msg,strlen(msg),0);
		}
		p=p->next;
	}
}

int main(int argc, const char *argv[])
{
	linklist head=creat_head();
	if(head==NULL)
	{
		perror("creat_head error");
		return -1;
	}

	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(-1==sfd)
	{
		perror("socket error");
		return -1;
	}
	printf("socket success sfd=%d\n",sfd);

	int reuse=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
	{
		perror("setsockopt error");
		return -1;
	}
	printf("端口号快速重用成功\n");

	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(SER_PORT);
	sin.sin_addr.s_addr=inet_addr(SER_IP);

	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("bind error");
		return -1;
	}
	printf("bind success\n");

	if(listen(sfd,128)==-1)
	{
		perror("listen error");
		return -1;
	}
	printf("listen success\n");

	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);

	char buf[256]="";

	fd_set readsfds;

	FD_ZERO(&readsfds);
	FD_SET(0,&readsfds);
	FD_SET(sfd,&readsfds);

	fd_set tempfds;

	int maxfd=sfd;
	
	while(1)
	{
		tempfds=readsfds;

		int res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(res==-1)
		{
			perror("select error");
			break;
		}
		else if(res==0)
		{
			printf("time out\n");
			continue;
		}

		if(FD_ISSET(sfd,&tempfds))
		{
			int new_fd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
			if(-1==new_fd)
			{
				perror("accept error");
				continue;
			}

			char username_buf[50]={0};
			ssize_t name_len=recv(new_fd,username_buf,sizeof(username_buf),0);
			if(name_len<=0)
			{
				perror("recv name error");
				close(new_fd);
				continue;
			}
			username_buf[name_len]='\0';

			if(insert_rear(new_fd,username_buf,cin,head)==0)
			{
				printf("新客户端:%s(fd=%d)\n",username_buf,new_fd);
				char join_msg[256];
				snprintf(join_msg,sizeof(join_msg),"[系统]%s登录",username_buf);
				broadcast(head,join_msg,-1);
			}

			FD_SET(new_fd,&readsfds);
			if(new_fd>maxfd)
			{
				maxfd=new_fd;
			}
			printf("[%s:%d] fd=%d username=%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),new_fd,username_buf);
		}
		
		//服务器向客户端发送信息
		if(FD_ISSET(0,&tempfds))
		{
			if(fgets(buf,sizeof(buf),stdin)==NULL)
			{
				perror("fgets error");
				continue;
			}
			
			if(strlen(buf)==0)
			{
				continue;
			}

			char system_msg[2048];
			snprintf(system_msg,sizeof(system_msg),"[系统公告]:%s",buf);
			broadcast(head,system_msg,-1);
		}

		for(int i=sfd+1;i<=maxfd;i++)
		{
			if(FD_ISSET(i,&tempfds))
			{
				char rbuf[128]="";
				ssize_t res=recv(i,rbuf,sizeof(rbuf)-1,0);
				if(res==0)
				{
					const char *username=find_username(head,i);
					printf("客户端%s(fd=%d)已下线\n",username,i);

					char leave[256];
					snprintf(leave,sizeof(leave),"[系统]:%s下线",username);
					broadcast(head,leave,i);

						close(i);
					FD_CLR(i,&readsfds);
					delete_client(head,i);

					if(i=maxfd)
					{
						for(int j=maxfd-1;j>=sfd;j--)
						{
							if(FD_ISSET(j,&readsfds))
							{
								maxfd=j;
								break;
							}
						}
					}
					continue;
				}

			if(res==-1)
			{
				perror("recv error");
				close(i);
				FD_CLR(i,&readsfds);
				delete_client(head,i);
				continue;
			}

			rbuf[res]='\0';

			const char *sender_name=find_username(head,i);

			char fullmsg[512];
			snprintf(fullmsg,sizeof(fullmsg),"[%s]:%s",sender_name,rbuf);

			broadcast(head,fullmsg,i);
			}
		}
	}

	close(sfd);

	linklist curr=head->next;
	while(curr!=NULL)
	{
		linklist next=curr->next;
		close(curr->data);
		free(curr);
		curr=next;
	}
	free(head);
	return 0;
}

客户端代码:

cs 复制代码
#include <25061head.h>

#define SER_PORT 8888
#define SER_IP "192.168.109.126"

int cfd;

void *callback(void* arg)
{
	char buf[256];
	while(1)
	{
		ssize_t res=recv(cfd,buf,sizeof(buf)-1,0);
		if(res<=0)
		{
			printf("与服务器断开连接\n");
			close(cfd);
			exit(0);
		}
		buf[res]='\0';
		printf("%s\n",buf);
		fflush(stdout);
	}
	return NULL;
}

int main(int argc, const char *argv[])
{
	if(argc!=4)
	{
		printf("%s[用户名][服务器IP][端口号]\n",argv[0]);
		return -1;
	}
	const char *username=argv[1];
	const char *system_ip=argv[2];
	int port=atoi(argv[3]);

	cfd=socket(AF_INET,SOCK_STREAM,0);
	if(-1==cfd)
	{
		perror("socket error");
		return -1;
	}
	printf("socket success cfd=%d\n",cfd);

	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(port);
	sin.sin_addr.s_addr=inet_addr(system_ip);

	if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("connect error");
		return -1;
	}
	printf("连接成功\n");

	send(cfd,username,strlen(username),0);

	pthread_t thread=-1;
	if(pthread_create(&thread,NULL,callback,NULL)!=0)
	{
		printf("线程创建失败\n");
		close(cfd);
		return -1;
	}
	pthread_detach(thread);

	char buf[256];
	while(1)
	{
		if(fgets(buf,sizeof(buf),stdin)==NULL)
		{
			break;
		}

		if(strcmp(buf,"quit")==0)
		{
			break;
		}

		send(cfd,buf,strlen(buf),0);
	}
	close(cfd);
	return 0;
}

结果:

相关推荐
CoovallyAIHub1 小时前
线性复杂度破局!Swin Transformer 移位窗口颠覆高分辨率视觉建模
深度学习·算法·计算机视觉
点云SLAM1 小时前
Eigen中Dense 模块简要介绍和实战应用示例(最小二乘拟合直线、协方差矩阵计算和稀疏求解等)
线性代数·算法·机器学习·矩阵·机器人/slam·密集矩阵与向量·eigen库
Jayyih2 小时前
嵌入式系统学习Day19(数据结构)
数据结构·学习
renhongxia12 小时前
大模型微调RAG、LORA、强化学习
人工智能·深度学习·算法·语言模型
PyHaVolask2 小时前
链表基本运算详解:查找、插入、删除及特殊链表
数据结构·算法·链表
高山上有一只小老虎2 小时前
走方格的方案数
java·算法
吧唧霸2 小时前
golang读写锁和互斥锁的区别
开发语言·算法·golang