服务端
运行环境: centos7
编译命令: g++ server.cpp -o server -lpthread
(链接pthread线程动态链接库)
#include <stdio.h>
#include <errno.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
int arr[100];
int host = 0;
struct parameter
{
int clifd; //arg1
int cnt; //arg2
};
bool is_exist(int fd) //遍历检测客户端�
{
int i;
for(i=0; arr[i]; i++)
{
// printf("arr[%d] = %d
",i,arr[i]);
if(fd == arr[i]) return true;
}
return false;
}
bool IsSocketClosed(int clientSocket) //TCP心跳检测
{
char buff[32];
int recvBytes = recv(clientSocket, buff, sizeof(buff), MSG_PEEK);
int sockErr = errno;
// printf("sockErr = %d",sockErr);
if( recvBytes > 0) //Get data
return false;
if( (recvBytes == -1) && (sockErr == EWOULDBLOCK) ) //No receive data
return false;
return true;
}
void* start_run(void* arg) //泛型指针变量
{
struct parameter *p =(parameter*)arg;
int i;
int clifd = *(int*)arg;
int cnt = p->cnt;
printf("%d
", cnt);
char buf[1024] = {};
// printf("%d
", strlen(arr));
while(true)
{
recv(clifd,buf,sizeof(buf),0);
char* prefix = " 当前在线人数【";
char* suffix = "】";
if (strlen(buf) != 0)
{
sprintf(buf,"%s%s%d%s",buf,prefix,cnt,suffix);
printf("%s
", buf);
if(strlen(buf) != 0)
{
printf("%s
",buf);
}
}
for(i=0; arr[i]; i++)
{
if(arr[i] != clifd)
{
// char* buf = (char*) malloc(strlen(buf) +strlen(cnt));
send(arr[i],buf,strlen(buf)+1,0);
}
}
if(strlen(buf) != 0 && 0 == strcmp("quit",strchr(buf, ':')+1) || IsSocketClosed(clifd))
{
host--;
close(clifd);
pthread_exit(NULL);
}
}
}
int main()
{
printf("服务器创建socket...
");
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(0 > sockfd)
{
perror("socket");
return -1;
}
printf("准备地址...
");
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(7767);
addr.sin_addr.s_addr = inet_addr("172.17.109.66");
socklen_t len = sizeof(addr);
printf("绑定socket与地址...
");
if(bind(sockfd,(struct sockaddr*)&addr,len))
{
perror("bind");
return -1;
}
printf("设置监听...
");
if(listen(sockfd,5))
{
perror("listen");
return -1;
}
struct parameter *par = new parameter;
int cnt = 0;
printf("等待客户端连接...
");
while(true)
{
struct sockaddr_in addrcli = {};
int clifd = accept(sockfd,(struct sockaddr*)&addrcli,&len);
if(0 > clifd)
{
perror("accept");
continue;
}
if(!is_exist(clifd))
{
arr[cnt] = clifd;
// printf("cnt = %d, clifd = %d
",cnt,clifd);
cnt++;
}
par->clifd = clifd;
par->cnt = cnt;
pthread_t pid;
int flag = pthread_create(&pid, NULL, start_run, (void*)par);
host++;
if (flag == -1)
{
/* code */
printf("create error!
");
return 1;
}
}
}
客户端
运行环境: window cmd
编译环境: clion
+ mingw64
动态链接dll库: 生成exe文件需将libstdc++-6.dll
,libwinpthread-1.dll
与exe文件置于同一文件目录下已备exe文件调用。
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <Windows.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "pthreadVC2.lib") //链接动态线程库
#define ONEBYTE 1024
struct parameter
{
int sktCli;//参数1
char* name;//参数2
};
void* start_send(void* arg) //发送聊天消息
{
struct parameter *p =(parameter*)arg;
int sockfd = *(int*)arg;
char buf[ONEBYTE] = {};
char buf1[ONEBYTE] = {};
while (true)
{
// char* prefix = ">>>";
gets(buf);
// sprintf(buf,"%s%s",prefix,buf);
sprintf(buf1, "%s:%s", p->name, buf);
send(sockfd,buf1,strlen(buf1)+1,0); //数据写入
if(0 == strcmp("quit",buf)) //quit退出聊天室
{
printf("***退出聊天室***
");
pthread_exit(NULL); //结束线程
}
}
}
void* start_recv(void* arg)
{
int sockfd = *(int*)arg;
char buf[ONEBYTE] = {};
while(true)
{
recv(sockfd,buf,sizeof(buf),0);//读取缓冲区数据
printf("%s
",buf);
}
}
int main(int argc, char *argv[]) {
//初始化DLL
WSADATA wd;
WSAStartup(MAKEWORD(2, 2), &wd);
//创建客户端套接字
int sktCli = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in addrSer = {0};
addrSer.sin_family = AF_INET; //设置IPV4协议
addrSer.sin_port = htons(7767); //设置服务器的端口
addrSer.sin_addr.s_addr = inet_addr("47.94.170.97"); //设置服务器公网IP
//连接服务器
connect(sktCli, (sockaddr *)&addrSer, sizeof(addrSer));
struct parameter *par = new parameter;
puts("***欢迎来到十三月的聊天室***");
printf("Tips:退出请输入quit
");
printf("少侠请留名:");
char name[20] = {};//昵称初始化
gets(name);
if (strlen(name) == 0)
{
/* code */
strcpy(name,"无名氏");
}
par->sktCli = sktCli;
par->name = name;
pthread_t pid;
pthread_create(&pid, NULL, start_recv, &sktCli); //创建接收消息线程
pthread_create(&pid, NULL, start_send, (void*)par); //创建发送消息线程
void* p = NULL;
pthread_join(pid, &p); //主线程等待pid1线程
WSACleanup();
return 0;
}
已编译打包好的客户端文件
链接:https://pan.baidu.com/s/1BIimAH9GRI9XuaKrTfm4jQ
提取码:3tbq