C语言 聊天室核心功能

从早上折腾到现在,基本上把聊天室的核心功能做出来了。

嗯,从下午到晚上一直在调试各种bug。

出现如下错误:
1、段错误(在使用链表的时候,非法使用p_last空间,解决方案是直接不用p_last)
2、新建的链表节点没有放在堆区…然后各种问题…
2、出现内存溢出(结果发现,第二次write一个/n的时候是copy的上一行的…第三个参数没改)——这个纠结了半下午。最后改成1,然后瞬间通畅…
3、关于服务器和客户端的线程回收(分离)的问题没关注,导致陷入printf("\n")的死循环…(解决方案是分别在客户端和服务器里加一个判断,如果从对方的通讯节点里收到的字节数为空,那么就直接关闭通讯节点并结束线程)

4.现在貌似还有个问题,就是我malloc堆区的内存还没有地方释放,我正在思考在哪里free…

先上传代码吧。明天再改改。

服务器端:server.c

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

typedef struct node{
	int cfd;
	struct node *p_next;
}node;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
node head={0};
node tail={0};

void* func(){
	char buf[128];
//	node* p_tmp=NULL;
	pthread_mutex_lock(&mutex);
	node* p_tmp=&head;
	node* p_tmp1=&tail;
	pthread_mutex_unlock(&mutex);
	int cfd;
	for(;p_tmp!=p_tmp1;p_tmp=p_tmp->p_next){
		node* p_first = p_tmp;
		node* p_mid = p_first->p_next;
		if(p_mid == &tail){
			cfd = p_first->cfd;
		}
	}
	while(1){
		pthread_mutex_lock(&mutex);
		p_tmp=head.p_next;
		pthread_mutex_unlock(&mutex);
		bzero(buf,128);
		int r=read(cfd,buf,128);
		if(r==0){
			printf("%d:关闭套接字,结束线程",cfd);
			
			close(cfd);
			pthread_exit(0);
		}
		for(;p_tmp!=p_tmp1;p_tmp=p_tmp->p_next){
			node* p_first = p_tmp;
			node* p_mid = p_first->p_next;
			printf("%d:%s\n",cfd,buf);
			write(p_first->cfd,buf,r);
			printf("我发给了这个客户端:%d\n",p_first->cfd);
			write(p_first->cfd,"\n",1);
		}
	}
	return NULL;
}

int main(void){
	struct sockaddr_in peer_addr;
	socklen_t peer_addr_size;
	peer_addr_size=sizeof(peer_addr);
	int cfd;
	char IP[64];
	int sfd;
	struct sockaddr_in my_addr;
	node* p_node=NULL;
	head.p_next = &tail;
	tail.p_next = NULL;

	sfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sfd == -1)
		perror("socket");

	memset(&my_addr, 0, sizeof(struct sockaddr_in));
    
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(8080);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(sfd, (struct sockaddr *) &my_addr,
	sizeof(struct sockaddr_in)) == -1)
		perror("bind");

	if (listen(sfd, 5) == -1)
	perror("listen");

	pthread_t tid;
	void* tret;
	while(1){
		node* p_newThread= (node*)malloc(sizeof(node));
		p_newThread->cfd=accept(sfd,(struct sockaddr*)&peer_addr,&peer_addr_size);
		p_newThread->p_next=NULL;

		if(p_newThread->cfd==-1)perror("accept");
		for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
			node* p_first = p_node;
			node* p_mid = p_first->p_next;
			if(p_mid==&tail){
				p_first->p_next = p_newThread;
				p_newThread->p_next = p_mid;
			}
		}
		printf("%d\n",p_newThread->cfd);


		printf("IP:%s\n",inet_ntop(AF_INET,
						&peer_addr.sin_addr,IP,64));
		pthread_create(&tid,NULL,func,NULL);
   }
   close(sfd);
   return 0;
}

客户端:client.c

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


void* func(void* arg){
	int fd=*(int*)arg;
	char buf[128];
	while(1){
		bzero(buf,128);
		int r=read(fd,buf,128);
		if(r==0)break;
		write(1,buf,r);
		write(1,"\n",1);
		bzero(buf,128);
	}
	exit(0);
	return (void *)0;
}

int main(int argc,char* argv[]){
	char msg[128];
	struct sockaddr_in serv;

	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd==-1){perror("socket");return -1;}

	serv.sin_family=AF_INET;
	serv.sin_port=htons(8080);
	inet_pton(AF_INET,argv[1],&serv.sin_addr);

	int c = connect(fd, (struct sockaddr*)&serv,sizeof(serv));
	if(c==-1){perror("connect");return -1;}
	while(1){
		pthread_t tid;
		pthread_create(&tid,NULL,func,&fd);
		bzero(msg,128);
		gets(msg);
		write(fd,msg,strlen(msg));
	}
	return 0;
}

Ubuntu16.04和macOS10.13.2
实测已经成功。

也请大牛们多多指教啊。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值