linux C下采用TCP网络协议实现同一局域网下的简单的网络聊天

linux C下采用TCP网络协议实现同一局域网下的简单的网络聊天

平台:
虚拟机:VMware-workstation-full-15.5.0
ubuntu:Ubuntu-16.04-64位
实现方法:采用多线程实现
编译:gcc -prthead server.c -o server
gcc -prthead server.c -o server
执行:./server+本机IP
./client+服务器IP+服务器端口

服务器代码 server.c

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

#define PORT         8888	//端口号
#define LISTEN_MAX   1024	//最大监听数,即最多允许连接1024个客户端,可自行更改
#define client_MAX   1024

typedef struct sockaddr     SA;
typedef struct sockaddr_in  SIN;

int i=0;
char r_buf[64];
int serfd,clifd[client_MAX]={0};
pthread_t tid[1024]={0};//线程tid
socklen_t addrlen;
SIN seraddr,cliaddr;

int Socket(int domain,int type,int protocol);
void ser_msg(char *argv);
int Bind(int sockfd,struct sockaddr* my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr*addr,socklen_t *addrlen);
void *task(void *arg);
void TIME(void);
int main(int argc,char *argv[])
{
	//创建套接字
	serfd=Socket(AF_INET,SOCK_STREAM,0);
	//服务器地址信息
	ser_msg(argv[1]);
	//绑定
	Bind(serfd,(SA*)&seraddr,sizeof(SA));
	//创建监听队列
	Listen(serfd,LISTEN_MAX);
	printf("欢迎来到群聊天,我是服务器\r\n");
	while(1)
	{
		
		clifd[i]=Accept(serfd,(SA*)&cliaddr,&addrlen);
		printf("有新的客户端:%d连接成功  ",clifd[i]);
		TIME();
		pthread_create(&tid[i],NULL,task,(void*)clifd[i]);
		i++;
	}
	close(serfd);
	return 0;
}

void *task(void *arg)
{
	int recvlen;
	char cli_name[64]={0};
	recv((intptr_t)(int *)arg,r_buf,sizeof(r_buf),0);
	strcpy(cli_name,r_buf);
	if(*r_buf!=0)
	{
		printf("%s加入聊天    ",r_buf);
		TIME();
	}
	bzero(&r_buf,sizeof(r_buf));
	int j=0;
	while(1)	
	{
		recvlen=recv((intptr_t)(int *)arg,r_buf,sizeof(r_buf),0);
		if(*r_buf==0)
		{
			close((intptr_t)(int *)arg);
			if(*cli_name!=0)
			{
				printf("%s离开群聊   ",cli_name);
				TIME();
			}
			else
			{
				printf("有客户端断开连接\r\n");
			}
			pthread_exit(NULL);
		}
		for(j=0;j<=i;j++)
		{
			if((intptr_t)(int *)arg==clifd[j])
			{
				continue;
			}
			send(clifd[j],r_buf,sizeof(r_buf),0);
		}
		printf("%s   ",r_buf);
		TIME();
		bzero(&r_buf,sizeof(r_buf));
	}
}

int Socket(int domain,int type,int protocol)
{
	int serfd;
	serfd=socket(domain,type,protocol);
	if(serfd==-1)
	{
		perror("连接服务器失败!\r\n");
		exit(0);
	}
	return serfd;
}
void ser_msg(char *argv)
{
	bzero(&seraddr,sizeof(SIN));
	seraddr.sin_family=AF_INET;
	seraddr.sin_port=htons(PORT);
	seraddr.sin_addr.s_addr=inet_addr(argv);
}
int Bind(int sockfd,struct sockaddr* my_addr,int addrlen)
{
	int ret;
	ret=bind(sockfd,my_addr,addrlen);
	if(ret==-1)
	{
		perror("绑定失败!\r\n");
		exit(0);
	}
	return 0;
}
int Listen(int s,int backlog)
{
	int ret;
	ret=listen(s,backlog);
	if(ret==-1)
	{
		perror("监听失败\r\n");
		exit(0);
	}
	return 0;
}
int Accept(int s,struct sockaddr*addr,socklen_t *addrlen)
{
	int clifd;
	clifd=accept(s,addr,addrlen);
	if(clifd ==-1)
	{
		perror("客户端连接失败!\r\n");
		exit(0);
	}
	return clifd;
}
void TIME(void)
{
	char *wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; 
    	time_t timep; 
    	struct tm *p; 
    	time(&timep); 
    	p = localtime(&timep); /*取得当地时间*/ 
    	printf(" %d/%d/%d ", (1900+p->tm_year),( 1+p->tm_mon), p->tm_mday); 
    	printf(" %s %d:%d:%d\r\n", wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec);
}

客户端代码 client.c

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

#define SERVER_IP "192.168.1.16"
#define PORT_NUM  1234
typedef struct sockaddr SA;
typedef struct sockaddr_in SIN;

int serfd;
char t_buf[64];
char r_buf[64];
char name[64];
int recv_len;
int send_len;

void *task1(void *arg);
void *task2(void *arg);
void TIME(void);

int main(int argc,char *argv[])
{
	int ret;
	pthread_t tid1,tid2;
	SIN seraddr;
	/*******建立套接字**********/
	serfd=socket(AF_INET,SOCK_STREAM,0);
	if(serfd==-1)
	{
		perror("socket failed\r\n");
		exit(0);
	}
	/************客户端地址信息**********/
	
	bzero(&seraddr,sizeof(SIN));
	seraddr.sin_family=AF_INET;
	seraddr.sin_port=htons(atoi(argv[2]));
	seraddr.sin_addr.s_addr=inet_addr(argv[1]);
	/**************连接服务器*************/
	ret = connect(serfd,(SA*)&seraddr,sizeof(SA));
	if(ret == -1)
	{
		perror("connect failed\r\n");
		exit(0);
	}
	printf("连接成功\r\n");
	printf("给自己取个名字吧:");
	scanf("%s",name);
	printf("请开始你的表演,输入大写Q退出聊天\r\n");
	send(serfd,name,sizeof(name),0);
	//创建线程
	pthread_create(&tid1,NULL,task1,(void *)1);
	pthread_create(&tid2,NULL,task2,(void *)2);
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	close(serfd);
	exit(0);
}
//发送
void *task1(void *arg)
{
	char t1_buf[64]={0};
	while(1)
	{
		strcat(t1_buf,name);
		strcat(t1_buf,":");
		scanf("%s",t_buf);
		if(strcmp(t_buf,"Q")==0)
		{
			printf("你已退出群聊    ");
			TIME();
			exit(0);
		}
		strcat(t1_buf,t_buf);
		send_len=send(serfd,t1_buf,sizeof(t1_buf),0);
		TIME();
		bzero(&t1_buf,sizeof(t1_buf));
	}
}
//接收
void *task2(void *arg)
{
	while(1)
	{
		recv_len=recv(serfd,r_buf,sizeof(r_buf),0);
		if(*r_buf==0)
		{
			printf("服务器断开,聊天被迫终止    ");
			TIME();
			exit(0);
		}
		printf("%s   ",r_buf);
		TIME();
		bzero(&r_buf,sizeof(r_buf));
	}
}
void TIME(void)
{
	char *wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; 
    	time_t timep; 
    	struct tm *p; 
   	time(&timep); 
   	p = localtime(&timep); /*取得当地时间*/ 
    	printf("%d/%d/%d ", (1900+p->tm_year),( 1+p->tm_mon), p->tm_mday); 
    	printf(" %s %d:%d:%d\r\n", wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec);
}

效果图

效果图

总结:每次有客户端连接成功就会创建一个线程。程序有很多可以完善的地方,可以加互斥锁,人数上限提示等,服务器没有键盘输入功能。线程传参那里,编译时会有一个警告(希望有大佬解决),但不影响程序执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值