#include "stdio.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#define SERVERIP "192.168.0.1"
#define SERVERPORT 222
#include<windows.h>
#include<iostream>
//接收文件函数
int RecvFile(SOCKET sock, char file_name_into[10]);
//转发文件函数
int SendFile(SOCKET sock, char filename[512]);
//是否在接收文件标志
int is_recFile = 0;
void Show_txt(char tj);
struct Clients_Socket {
char IP[20];
char Name[40];
SOCKET sClient;
char buf[512];
char other[10];
};
//定义结构体数组
struct Clients_Socket clients[100];//一百个客户端
int Status = 0;
int clientsize = 0;
HANDLE handel[100];
int first = 0;
//文件存储
FILE* fp;
//原来
int ret;
char sendBuf[512], recvBuf[512];
WSADATA data;
SOCKET sockListen, sockTongxun;
struct sockaddr_in addrServer, cli;
int len;
//是否打开聊天显示
int is_open = 1;
//接送消息并转发函数//***********//
DWORD WINAPI rev(LPVOID lpParameter)
{
int xx = 0;
int Fileing = 0;
int socketid = 0;
socketid = clientsize;
char recvb[512];
//ke
int qw = 1;
while (1) {
memset(recvb, 0, sizeof(recvb));
//接送函数
if (Fileing == 0) { //判断是否在进行发送文件操作
ret = recv(clients[socketid].sClient, recvb, sizeof(recvb), 0);
if (ret < 1) {//判断客户端是否关闭
printf("客户端已关闭socket(%d\n)", socketid);
clients[socketid].sClient = -1;
break;
}
}
else { printf("正在发送文件...\n"); continue; }
char bb[512];
strcpy(bb, recvb);
//
char s[512];
memset(s, 0, sizeof(s));
s[0] = '#';
s[1] = (char)socketid + 65;
s[2] = '#';
s[3] = ':';
//存放用户名
for (int ii = 4; ii < strlen(bb) + 4; ii++) {
s[ii] = bb[ii - 4];
}
//判断是否有私聊指令
if (strlen(bb) > 5) { //********************************私聊功能****************************************//
int index0 = 0, index1 = 0, index2 = 0;
int in0 = 0, in1 = 0, in2 = 0, in3 = 0;
int sl0 = 0, sl1 = 0, sl2 = 0, sl3 = 0;
index0 = (bb[0] == 's');//私聊判断
index1 = (bb[1] == 't');
index2 = (bb[2] == 'o');
sl0 = (bb[0] == 's');//查询在线客户端情况
sl1 = (bb[1] == 'h');
sl2 = (bb[2] == 'o');
sl3 = (bb[3] == 'w');
in0 = (bb[0] == 'f');//文件判断
in1 = (bb[1] == 'i');
in2 = (bb[2] == 'l');
in3 = (bb[3] == 'e');
int index3 = bb[3];
if (index0 == 1 && index1 == 1 && index2 == 1)
{//是私聊信息
//解密对方要发送私聊给谁
//私聊
if ((index3 - 65 < clientsize) && (clients[index3 - 65].sClient != -1)) {///////////////////*****昨天
//printf("私聊对象是%d\t客户端:%d\t在线客户端%d\n",index3,socketid,clientsize);
if (socketid != index3 - 65) { //私聊的不是自己
//printf("index3=%d",index3-65);
send(clients[index3 - 65].sClient, s, strlen(s), 0);
//文件保存
fp = fopen("D:\\record.txt", "a");
fwrite(s, strlen(s) + 5, 1, fp);
fprintf(fp, "\n");
fclose(fp);
if (is_open == 1) {
printf("私聊->%s\n", s);
}
}
else { //不可以私聊自己
char no_sl[512] = { "#服务器提醒#:不可私聊自己!" };
send(clients[socketid].sClient, no_sl, strlen(no_sl), 0);
printf("\n不能私聊自己\n");
printf("不能私聊自己");
}
}
else if (clients[index3 - 65].sClient == -1) {
//私聊对象已下线
char out_online[512];
memset(out_online, 0, sizeof(out_online));
strcpy(out_online, "#服务器#:对方已下线,无法私聊!");
send(clients[socketid].sClient, out_online, strlen(out_online), 0);
}
else if (index3 - 64 > clientsize && clients[index3 - 65].sClient != -1) {//******************************************************************************昨天
printf("------(%d)\n", index3 - 65);
//私聊时,对方不在线;///////////////////////////////**********私聊对方,对方不在线***************///////////////////////////////
char no_sl[512];
memset(s, 0, sizeof(s));
strcpy(no_sl, "#服务器#:对方不在线,无法私聊!");
send(clients[socketid].sClient, no_sl, strlen(no_sl), 0);
}
}
else if ((in0 == 1 && in1 == 1 && in2 == 1 && in3 == 1)) { //********************************文件发送功能********************//
char persion = bb[4];
int File_len = strlen(bb);
char File_an[512];//发送的文件路径即文件名
char File_type[10];
printf("\n需要转发给客户端%c\t对应结构体数组=%d\n", persion, persion - 65);
//初始化数组
memset(File_an, 0, sizeof(File_an));
memset(File_type, 0, sizeof(File_type));
for (int i = 0; i < File_len - 5; i++) {
File_an[i] = bb[i + 5];
}
File_type[6] = bb[File_len - 1];
File_type[5] = bb[File_len - 2];
File_type[4] = bb[File_len - 3];
File_type[3] = bb[File_len - 4];
char F1 = (rand() % 25) + 65;
char F2 = (rand() % 25) + 65;
char F3 = (rand() % 25) + 65;
File_type[2] = F1;
File_type[1] = F2;
File_type[0] = F3;
//printf("发送的文件路径、是%s\t文件类型是%s\n",File_an,File_type);
Fileing == 1;
int cx = 1; //**************************开始接收文件********************//
cx = RecvFile(clients[socketid].sClient, File_type);
while (1) {
if (cx == 0) {
if (clients[persion - 65].sClient > 0 && clients[persion - 65].sClient != -1) { //******************转发文件给客户端*************************//
send(clients[persion - 65].sClient, bb, strlen(bb), 0);
//
SendFile(clients[persion - 65].sClient, File_type);
}
else {
printf("\n对方客户端不在线,不能转发发送文件\n");
char no_sl[512];
memset(s, 0, sizeof(s));
strcpy(no_sl, "#服务器#:对方不在线,文件发送失败!!");
send(clients[socketid].sClient, no_sl, strlen(no_sl), 0);
}
Fileing == 0;
break;
}
}
}
else if (sl0 == 1 && sl1 == 1 && sl2 == 1 && sl3 == 1) { //***************************查询客户端在线情况******************//
//客户端发来信息,要查询谁在线;
if (bb[4] == 'm' && bb[5] == 'e') { //查询自己客户端情况
char online[512];
memset(online, 0, sizeof(online));
online[0] = 'm';
online[1] = 'e';
online[2] = ':';
online[3] = '[';
online[4] = socketid + 65;
online[5] = ']';
send(clients[socketid].sClient, online, strlen(online), 0);
}
else { //查询所有客户端情况
char online[512];
memset(online, 0, sizeof(online));
online[0] = 'o';
online[1] = 'n';
online[2] = 'l';
online[3] = 'i';
online[4] = 'n';
online[5] = 'e';
online[6] = ':';
int size = 7;
for (int i = 0; i < 100; i++) {
if (clients[i].sClient > 0 && clients[i].sClient != -1) {
//printf("在线客户端:%c\tClient=:%d\tIP地址:%s\n",(i+65),clients[i].sClient,clients[i].IP);
online[size] = '[';
online[size + 1] = char(i + 65);
online[size + 2] = ']';
online[size + 3] = ',';
size = size + 4;
}
}
send(clients[socketid].sClient, online, strlen(online), 0);
}
}
else { //不是私聊信息
int one_jilu = 1;
int clients_online = 0;//群聊人数
for (int i = 0; i < 100; i++) {
if (clients[i].sClient > 0 && clients[i].sClient != -1) {
if (clients[i].sClient != clients[socketid].sClient) {
ret = send(clients[i].sClient, s, strlen(s), 0);
clients_online++;
if (one_jilu == 1) {//群聊记录在服务器只显示一次
//文件保存
fp = fopen("D:\\record.txt", "a");
fwrite(s, strlen(s) + 5, 1, fp);
fprintf(fp, "\n");
fclose(fp);
if (is_open == 1) {
printf("\n群聊e->%s\n", s);
one_jilu = 0;
}
one_jilu = 0;
}
}
//单用户在线//****************************//
if (clientsize == 1) {
//文件保存
if (is_open == 1) {
printf("\n单用户在11线->%s\n", s);
}
fp = fopen("D:\\record.txt", "a");
fwrite(s, strlen(s) + 5, 1, fp);
fprintf(fp, "\n");
fclose(fp);
}
}
}
if (clients_online == 0) {//除了自己无人在线
char no_sl[512];
memset(s, 0, sizeof(s));
strcpy(no_sl, "#服务器#:未发现有人在线,无法群聊!!");
send(clients[socketid].sClient, no_sl, strlen(no_sl), 0);
clients_online = 0;
}
}
}
//输入的字符串长度小于5,不可能是私聊
else {
////////////////////-------------**转发消息**-------------///////////////////
int one_jilu2 = 1;
int clients_online = 0;//群聊人数
for (int i = 0; i < 100; i++) {
if (clients[i].sClient > 0 && clients[i].sClient != -1) {
if (clients[i].sClient != clients[socketid].sClient) {
ret = send(clients[i].sClient, s, strlen(s), 0);
clients_online++;
if (one_jilu2 == 1) {
if (is_open == 1) {
printf("群聊2-》%s\n", s);
}
//文件保存
fp = fopen("F:\\record.txt", "a");
fwrite(s, strlen(s) + 5, 1, fp);
fprintf(fp, "\n");
fclose(fp);
one_jilu2 = 0;
}
}
//只有自己一个用户在线//***************************//
if (clientsize == 1) {
//文件保存
if (is_open == 1) {
printf("\n单用户在线22->%s\n", s);
}
fp = fopen("F:\\record.txt", "a");
fwrite(s, strlen(s) + 5, 1, fp);
fprintf(fp, "\n");
fclose(fp);
}
}
}
if (clients_online == 0) {//除了自己无人在线
char no_sl[512];
memset(s, 0, sizeof(s));
strcpy(no_sl, "#服务器#:未发现有人在线,无法群聊!!");
send(clients[socketid].sClient, no_sl, strlen(no_sl), 0);
clients_online = 0;
}
}//else结尾
//*///
}//**************************************** while循环 *******************************************************//
printf("\n");
return 0L;
}
//*******///
//socket接收
DWORD WINAPI getsocket(LPVOID lpParameter)
{
while (1) {
int lens = sizeof(sockaddr);
sockTongxun = accept(sockListen, (struct sockaddr*)&cli, &lens);
if (INVALID_SOCKET == sockTongxun)
{
printf("accept 错误");
return -5;
}
if (is_open == 1) {
printf("接收一个客户端ip和端口:%s:%d下面开始通信\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));
}
//初始化buff
char sendbuff[512];
memset(sendbuff, 0, sizeof(sendbuff));
//赋值给结构体数组
clients[clientsize].sClient = sockTongxun;
strcpy(clients[clientsize].Name, "张三");
strcpy(clients[clientsize].IP, inet_ntoa(cli.sin_addr));
strcpy(clients[clientsize].buf, sendbuff);
strcpy(clients[clientsize].other, "已连接");
printf("\n");
handel[clientsize] = CreateThread(NULL, 0, rev, NULL, 0, NULL);
//必须睡觉,不然rev函数接收的clientsize会大1
Sleep(10);
//**********************************************************************************************列表展示--有用户登录就发送
char online[512];
memset(online, 0, sizeof(online));
online[0] = 'o';
online[1] = 'n';
online[2] = 'l';
online[3] = 'i';
online[4] = 'n';
online[5] = 'e';
online[6] = ':';
int size = 7;
for (int i = 0; i < 100; i++) {
if (clients[i].sClient > 0 && clients[i].sClient != -1) {
online[size] = '[';
online[size + 1] = char(i + 65);
online[size + 2] = ']';
online[size + 3] = ',';
size = size + 4;
}
}
send(clients[clientsize].sClient, online, strlen(online), 0);
//*******************************************************************************************************列表展示
clientsize++;
}
return 0L;
}
int main(void)
{
ret = WSAStartup(MAKEWORD(2, 2), &data);
if (SOCKET_ERROR == ret)
{
printf("WSAStartup 错误");
return -1;
}
sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sockListen)
{
printf("socket 错误");
return -2;
}
addrServer.sin_addr.S_un.S_addr = inet_addr(SERVERIP);
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT);
len = sizeof(sockaddr);
ret = bind(sockListen, (const sockaddr*)&addrServer, len);
//ret = bind(sockListen, (const sockaddr*)&addrServer, sizeof(SOCKADDR_IN));
if (SOCKET_ERROR == ret)
{
printf("bind 错误");
closesocket(sockListen);
WSACleanup();
return -3;
}
ret = listen(sockListen, 1);
if (SOCKET_ERROR == ret)
{
printf("listen 错误");
return -4;
}
printf("//***************服务器启动成功****************//.\n\n");
//开启接送socket线程
HANDLE thread1 = CreateThread(NULL, 0, getsocket, NULL, 0, NULL);
//********************************上面是服务端接送数据*****************************************//
while (true) {
printf("\n||*******0.关闭聊天显示*********||\n");
printf("||*******1.开启聊天显示*********||\n");
printf("||*******2.查询聊天记录*********||\n");
printf("||*******3.关闭服务器***********||\n");
printf("||*******4.查询在线情况*********||\n");
printf("||*******5.查询客户端情况*******||\n\n");
char c;
c = getchar();
getchar();
printf("输入了%d\n", c);
//功能点判断
if (c != 's') {
switch (c) {
case '0':
is_open = 0;
printf("已经关闭聊天记录显示\n");
break; //退出 switch
case '1':
is_open = 1;
printf("已经开启聊天记录显示\n");
break; //退出 switch
case '2':
printf("\n请输入要查找的客户端名:如 A,或按0查询全部!\n");
char cc;
cc = getchar();
getchar();
Show_txt(cc);
break;
case '4':
{
int sizes = 0;
for (int i = 0; i < 100; i++) {
if (clients[i].sClient > 0 && clients[i].sClient != -1) {
printf("在线客户端:%c\tClient=:%d\tIP地址:%s\n", (i + 65), clients[i].sClient, clients[i].IP);
sizes++;
}
}
printf("在线人数:%d\n", sizes);
break;
}
case '5':
{
printf("请输入要查看的客户端\n");
char c;
c = getchar();
getchar();
int indexs = c - 65;
if (indexs > -1) {
printf("socket=%d\n", clients[indexs].sClient);
if (clients[indexs].sClient > 0 && clients[indexs].sClient != -1) {
printf("正在使用中:IP=%s\n", clients[indexs].IP);
}
else if (clients[indexs].sClient == -1) {
printf("该客户端已下线,未在使用\n");
}
else if (clients[indexs].sClient == -0) {
printf("该客户端未被使用过\n");
}
}
else {
printf("未找到客户端%c\n", c);
}
break;
}
default:
printf("\n*****请按照序号表输入*****\n~");
}
}
else {
break;
}
}
closesocket(sockListen);
closesocket(sockTongxun);
WSACleanup();
system("pause");
return 0;
}
//////////////******************接收文件***********************//////////
int RecvFile(SOCKET sock, char file_name_into[10])
{
char File_name[512];
int fileLen_all = 0;
memset(File_name, 0, sizeof(File_name));
int xx = 0;
int ret;
FILE* fp;
char sendBuf[4096], recvBuf[4096], filename[512];
//设置超时时间//************************************//
int timeout = 1000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
strcpy(filename, file_name_into);//保存的文件名
strcpy(File_name, filename);
fp = fopen(filename, "wb");
if (NULL == fp)
{
return -3;
}
memset(recvBuf, 0, sizeof(recvBuf));
memset(sendBuf, 0, sizeof(sendBuf));
int all = 0;
int index = 0;
int out_time = 0;
//
int text = 0;
//-----------------------------------------------bug循环次数不能确定
while (1) {
out_time++;
//重置数组
memset(recvBuf, 0, sizeof(recvBuf));
ret = recv(sock, recvBuf, sizeof(recvBuf), 0);
if (ret == -1) {
break;
}
if (SOCKET_ERROR == ret)
{
return -6;
}
if (ret != 0) {
fwrite(recvBuf, ret, 1, fp);
text = ret + text;
index++;
}
}
printf("\n实际接收文件大小=%d", text);
fclose(fp);
printf("\n读取次数%d\n", index);
timeout = 100000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
return 0;
}
/////////***************转发文件函数*********************************//
int SendFile(SOCKET sock, char filename[512])
{
int ret, cnt, len1, lenlast;
char sendBuf[4096], recvBuf[4096];
FILE* fp;
int totlen;
fp = fopen(filename, "rb+");
if (NULL == fp)
{
printf("open file error\n");
return -1;
}
fseek(fp, 0, SEEK_END);
totlen = ftell(fp);
int x = totlen / 4096;
if (totlen % 4096 != 0) {
x = x + 1;
}
printf("\n\n/*************...文件操作中...*************************//");
printf("\n文件名:(%s)的长度为 %d字节\t需要发送%d次\n", filename, totlen, x);
memset(recvBuf, 0, sizeof(recvBuf));
//读取电脑文件,发送给客户端
rewind(fp);//从开头文件读取
int index = 0;
printf("发送文件中,请勿进行其他操作......\n");
//文件进度条
printf("进度条:》");
int File_ing = 0, alt = totlen / 50, ing = alt;
int fileLen_all = 0;
while (fileLen_all < totlen) {
//从新初始化数组
memset(sendBuf, 0, sizeof(sendBuf));
fread(sendBuf, 4096, 1, fp);//每次读取size个字符,到buff中
ret = send(sock, sendBuf, 4096, 0);
if (fileLen_all > ing) {
//进度条
printf("-");
ing = ing + alt;
}
index++;
fileLen_all = fileLen_all + ret;
if (SOCKET_ERROR == ret)
{
return -6;
}
}
fclose(fp);
printf("\n发送完毕\t实际发送文件大小为%d\n", fileLen_all);
printf("/****************...文件操作完...*******************//\n");
fileLen_all = 0;
}
//查询记录
void Show_txt(char tj) {
char c[1000];
FILE* fptr = fopen("F:/record.txt", "r");
int chars = 0;
printf("%c----", tj);
if (tj == '0') {
while (fgets(c, sizeof(c), fptr) != NULL)
{
printf("%s\n", c);
chars++;
}
}
else {
while (fgets(c, sizeof(c), fptr) != NULL)
{
if (c[1] == tj) {
printf("%s\n", c);
chars++;
}
}
}
printf("共查找到%d条记录\n", chars);
fclose(fptr);
}