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

结果:

相关推荐
rit84324998 分钟前
人工鱼群算法AFSA优化支持向量机SVM,提高故障分类精度
算法·支持向量机·分类
佩佩(@ 。 @)32 分钟前
嵌入式:走馬燈-stm32GPIOF_LED9、10; GPIOE_D10、D12 流水綫蜂鸣器
stm32·嵌入式硬件·算法
知彼解己37 分钟前
字符串大数相加:从初稿到优化的思路演进
java·开发语言·算法
haing20191 小时前
使用deboor法计算三次B样条曲线在参数为u处的位置的方法介绍
算法·b样条曲线·deboor
qq_352109521 小时前
旋转数字矩阵 od
算法
大阳1231 小时前
51单片机4(温度传感器DS18B20)
开发语言·单片机·嵌入式硬件·算法·51单片机
iナナ1 小时前
Java优选算法——二分查找
数据结构·算法·leetcode
l1t2 小时前
利用美团龙猫添加xlsx的sheet.xml读取sharedStrings.xml中共享字符串输出到csv功能
xml·c语言·数据结构·人工智能·算法·解析器
宇钶宇夕2 小时前
西门子 S7-200 SMART PLC 编程:转换 / 定时器 / 计数器指令详解 + 实战案例(指令讲解篇)
运维·算法·自动化
我叫汪枫2 小时前
Spring Boot图片验证码功能实现详解 - 从零开始到完美运行
java·前端·javascript·css·算法·html