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;
}

结果:

相关推荐
2401_8414956440 分钟前
【数据结构】红黑树的基本操作
java·数据结构·c++·python·算法·红黑树·二叉搜索树
西猫雷婶42 分钟前
random.shuffle()函数随机打乱数据
开发语言·pytorch·python·学习·算法·线性回归·numpy
小李独爱秋1 小时前
机器学习中的聚类理论与K-means算法详解
人工智能·算法·机器学习·支持向量机·kmeans·聚类
小欣加油3 小时前
leetcode 1863 找出所有子集的异或总和再求和
c++·算法·leetcode·职场和发展·深度优先
C++chaofan3 小时前
项目中为AI添加对话记忆
java·数据结构·人工智能·redis·缓存·个人开发·caffeine
十八岁讨厌编程3 小时前
【算法训练营Day27】动态规划part3
算法·动态规划
炬火初现4 小时前
Hot100-哈希,双指针
算法·哈希算法·散列表
weixin_307779135 小时前
利用复变函数方法计算常见函数的傅里叶变换
算法
共享家95276 小时前
LeetCode热题100(1-7)
算法·leetcode·职场和发展
失散136 小时前
软件设计师——03 数据结构(下)
数据结构·软考·图论·软件设计师