网络编程(0812-林雪阵)

 1,服务器代码:

 (1)头文件

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

//打印错误信息宏函数
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)

//定义用户结构体
typedef struct node{
	struct sockaddr_in cin;    //存储接收到的数据包来自哪里
	socklen_t addrlen;
	char name[20];
	int stop_speaking;
	int size;
	struct node* next;
}CLI;


//创建用户结构体信息链表
CLI* create();
//判断接收到是不是新成员
int judge(CLI *H,CLI*q);
//尾插法插入新用户
int insert_cli(int sfd,CLI *H,CLI**p,char *name);
//发送信息给其他成员
int senmsg(int sfd,CLI* H,CLI*q,char *msg);
//删除指定成员
int deleat_num(int sfd,CLI *H,CLI**q);

//显示现有成员
void show(CLI*H);
//禁言
int stop_speak(int sfd,CLI *H,char*name);
//踢出
int get_out(int sfd,CLI*H,char *name);
//取消禁言
int stat_speak(int sfd,CLI *H,char*name);

#endif

(2)功能代码

#include "head.h"

//创建用户结构体信息链表
CLI* create()
{
	CLI *H=(CLI*)malloc(sizeof(CLI));
	if(NULL==H)
	{
		puts("创建失败\n");
		return NULL;
	}
	//初始化
	H->next=NULL;
	H->size=0;
	H->stop_speaking=0;
	strcpy(H->name,"head");
	puts("创建链表成功");
	return H;
}

//判断接收到是不是新成员
int judge(CLI *H,CLI*q)
{
	//判断逻辑
	if(NULL==H)
	{
		printf("链表不存在\n");
		return -1;
	}
	//判断是不是空表
	if(0==H->size)
	{
		return 1;
	}
	//循环遍历是不是新成员
	CLI*p=H->next;
	while(p!=NULL)
	{
		if(p->cin.sin_port == q->cin.sin_port)
		{
			return 0;
		}
		p=p->next;
	}
	return 1;
}
//尾插法插入新用户
int insert_cli(int sfd,CLI *H,CLI**new,char *name)
{
	CLI *p=H;
	//偏移指针
	while(p->next!=NULL)
	{
		p=p->next;
	}
	//完成尾插
	p->next=*new;
	strcpy((*new)->name,name);
	(*new)->stop_speaking=0;

	//表的变化
	H->size++;
	//发送登录信息给其他成员
	strcat(name,"登录成功");

	p=H->next;
	while(p != *new)
	{
		if(sendto(sfd,name,strlen(name),0,(struct sockaddr*)&(p->cin),p->addrlen)<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		p=p->next;
	}

	return 0;
}
//发送信息给其他成员
int senmsg(int sfd,CLI* H,CLI*q,char *msg)
{

	//封装成员名在要发送的内容前
	char arr[200]="";
	CLI*find=H->next;
	while(find!=NULL)
	{
		if((find->cin).sin_port == (q->cin).sin_port)
		{
			if(find->stop_speaking==1)
			{
				return -1;
			}
			strcpy(arr,find->name);
			strcat(arr,":");
			strcat(arr,msg);
		
		}
		find=find->next;
	}

	CLI*p=H->next;
	//循环发送信息
	while(p!=NULL)
	{
		if((p->cin).sin_port == (q->cin).sin_port)
		{
			p=p->next;
			continue;
		}
		if(sendto(sfd,arr,strlen(arr),0,(struct sockaddr*)&(p->cin),p->addrlen)<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		p=p->next;
	}
	return 0;
}

//删除指定成员
int deleat_num(int sfd, CLI *H,CLI**qe)
{
	CLI *q=*qe;
	char arr[100]="";
	//找到对应要删除的节点,封装退出字符串
	CLI*find=H;
	while(find->next!=NULL)
	{
		if(find->next->cin.sin_port == q->cin.sin_port)
		{
			strcpy(arr,find->next->name);
			strcat(arr,"退出");
			break;
		}
	}
	//删除指定成员
	CLI*temp=find->next;
	find->next=temp->next;
	free(temp);
	temp=NULL;

	//发送退出信息给其他成员
	CLI *p=H->next;
	while(p!=NULL)
	{
		if(sendto(sfd,arr,strlen(arr),0,(struct sockaddr*)&(p->cin),p->addrlen)<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		p=p->next;
	}
	return 0;
}
//显示现有成员

void show(CLI*H)
{
	CLI*p=H->next;
	while(p!=NULL)
	{
		printf("遍历:%s\n",p->name);
		p=p->next;
	}
	return;
}
//禁言
int stop_speak(int sfd,CLI *H,char*name)
{
	CLI*p=H;
	while(p!=NULL)
	{
		if(strcmp(p->name,name)==0)
		{
			p->stop_speaking=1;
			char arr[20]="stoptalking";
			sendto(sfd,arr,sizeof(arr),0,(struct sockaddr*)&(p->cin),p->addrlen);
		}
		p=p->next;
	}
	return 0;
}
//取消禁言
int stat_speak(int sfd,CLI *H,char*name)
{
	CLI*p=H;
	while(p!=NULL)
	{
		if(strcmp(p->name,name)==0)
		{
			p->stop_speaking=0;
			char arr[20]="stattalking";
			sendto(sfd,arr,sizeof(arr),0,(struct sockaddr*)&(p->cin),p->addrlen);
		}
		p=p->next;
	}
	return 0;
}
//踢出
int get_out(int sfd,CLI*H,char *name)
{
	CLI*p=H;
	while(p!=NULL)
	{
		if(strcmp(p->name,name)==0)
		{
			//通知用户端退出
			char arr[200]="quit";
			sendto(sfd,arr,sizeof(arr),0,(struct sockaddr*)&(p->cin),p->addrlen);

			//找到对应要删除的节点,封装退出字符串
			strcpy(arr,name);
			strcat(arr,"退出");

			//删除指定成员
			CLI *find=H;
			while(find->next!=NULL)
			{
				if(find->next==p) break;
			}
			CLI*temp=find->next;
			find->next=temp->next;
			free(temp);
			temp=NULL;

			//发送退出信息给其他成员
			CLI *p1=H->next;
			while(p1!=NULL)
			{
				if(sendto(sfd,arr,strlen(arr),0,(struct sockaddr*)&(p1->cin),p1->addrlen)<0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				p1=p1->next;
			}	
			break;
		}
		p=p->next;
	}
	return 0;
}

(3)服务器主代码

#include "head.h"

int sfd=0;

void* sys_msg(void*arg)
{
	pthread_detach(pthread_self());
	CLI *H=(CLI*)arg;
	int num;

	while(1)
	{
		printf("************管理员************\n");
		printf("**      1,发送系统信息      **\n");
		printf("**      2,禁言              **\n");
		printf("**      3,踢出              **\n");
		printf("**      4,取消禁言          **\n");
		printf("******************************\n");
		printf("请输入选项:");
		scanf("%d",&num);
		getchar();
		switch(num)
		{
		case 1:
			{
				printf("请输入系统消息:");
				char buf[500]="";
				char arr[128]="";
				//系统信息输入
				bzero(arr,sizeof(arr));
				bzero(buf,sizeof(buf));
				strcpy(buf,"系统消息:");

				fgets(arr,sizeof(arr),stdin);
				arr[strlen(arr)-1]=0;
				strcat(buf,arr);
				CLI *p=H->next;

				//系统信息发送
				while(p!=NULL)
				{
					if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(p->cin),p->addrlen)<0)
					{
						ERR_MSG("sendto");
						return NULL;
					}
					p=p->next;
				}

			}
			break;
		case 2:
			{
				char name[20];
				printf("请输入要禁言的名字:");
				fgets(name,sizeof(name),stdin);
				name[strlen(name)-1]=0;
				stop_speak(sfd,H,name);
			}
			break;
		case 3:
			{
				char name[20];
				printf("请输入要踢出的名字:");
				fgets(name,sizeof(name),stdin);
				name[strlen(name)-1]=0;
				get_out(sfd,H,name);
			}
			break;
		case 4:
			{
				char name[20];
				printf("请输入要取消禁言的名字:");
				fgets(name,sizeof(name),stdin);
				name[strlen(name)-1]=0;
				stat_speak(sfd,H,name);
			}
			break;
		default:printf("输入错误,请重新输入\n"); break;
		}
	}
}



int main(int argc, const char *argv[])
{

	//创建套接字
	sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}

	//填充服务器的IP地址以及端口号
	struct sockaddr_in sin;
	sin.sin_family        = AF_INET;
	sin.sin_port          = htons(8888);
	sin.sin_addr.s_addr   = inet_addr("192.168.31.107");

	

	//绑定服务器的地址信息结构体
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");


	
	//创建用户结构体信息链表
	//头节点并初始化
	CLI *H=create();

	//创建发送系统信息线程
	pthread_t tid;
	if(pthread_create(&tid,NULL,sys_msg,(void*)H)!=0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}

	//接收用户发送的信息
	char buf[128]="";

	//接收
	while(1)
	{
		bzero(buf,sizeof(buf));

		//申请一个新的用户信息节点
		CLI *q=(CLI*)malloc(sizeof(CLI));
		q->next=NULL;
		q->addrlen=sizeof(q->cin);
		q->size=0;

		//接收信息
		if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->cin),&(q->addrlen))<0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}


		//判断是不是新用户
		if(1==judge(H,q))     //是新用户,链表新增,并发信息给
		{
			insert_cli(sfd,H,&q,buf);	
		}else
		{
			if(strcmp(buf,"quit")==0)
			{
				deleat_num(sfd,H,&q);
			}else{
				senmsg(sfd,H,q,buf);
			}
		}


	}

	close(sfd);
	return 0;
}

2,用户代码

 用户代码示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

//打印错误信息宏函数
#define ERR_MSG(msg) do{\
    fprintf(stderr,"__%d__",__LINE__);\
    perror(msg);\
}while(0)

int sfd=0;

void* recv1(void* reg)
{
	pthread_detach(pthread_self());
	struct sockaddr_in cin;
	char buf[300]="";
	socklen_t addrlen=sizeof(cin);

	while(1)
	{

      bzero(buf,sizeof(buf));                                                   
      if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen)<0)
      {
          ERR_MSG("recvfrom");
          return NULL;
      }
	  if(strcmp(buf,"quit")==0)
	  {
	  	printf("你被踢出群聊\n");
		exit(0);
	  }else if(strcmp(buf,"stoptalking")==0)
	  {
	  	printf("你已被禁言\n");
	  }else if(strcmp(buf,"stattalking")==0)
	  {
	  	printf("你被取消禁言\n");
	  }
	  else{
			  
      printf("%s\n",buf);
	  }
	}

}

int main(int argc, const char *argv[])
{
    //创建套接字
    sfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sfd<0)
    {
        ERR_MSG("socket");
        return -1;
    }                                                              

    //客户端
    struct sockaddr_in cin;
    cin.sin_family       = AF_INET;
    cin.sin_port         = htons(2222);
    cin.sin_addr.s_addr  = inet_addr("192.168.31.107"); 
    
    //绑定用户端的地址信息结构体
    if(bind(sfd,(struct sockaddr*)&cin,sizeof(cin))<0)           
    {
        ERR_MSG("bind");
        return -1;
    }


    //服务器
    struct sockaddr_in sin;
    sin.sin_family       = AF_INET;
    sin.sin_port         = htons(8888);
    sin.sin_addr.s_addr  = inet_addr("192.168.31.107");
	
	//连接服务器,并发送自己的名字	
    char buf[128]="";
	printf("请输入网名:");
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf)-1]=0;                                             
    if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("sendto");
		return -1;
	}

	pthread_t tid;
	if(pthread_create(&tid,NULL,recv1,(void*)&sin)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}


	while(1)
	{
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;
		sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
		if(strcmp(buf,"quit")==0)
		{
			exit(0);
		}

	}


    close(sfd);
	return 0;
}

 运行示例:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林某某..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值