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