本人刚接触c/c++不是特别久,所以很多地方的写法可能会比较蠢和复杂化,思路也不是特别明确,各位请见谅..
代码是在安卓手机软件"C4droid"上开发运行的,运行环境是linux.
程序即是客户端也是服务端,第一次使用先定义自己的用户名,用户名保存在本地文件中.
可以拿两部手机来测试,进入程序后,先输入'1'进行局域网嗅探在线的用户,时间可能比较久。
然后输入2文件传输,再输入需要配对用户的id即可进行传输.
另一台手机
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <pthread.h>
#include <vector>
#define CONFIG "/sdcard/Server/.config"
#define FULL_LEN 524288
#define TIMEOUT 1
char User_Name[32];
char YN = 'O';
int ipv4 = 0;
bool istrans = false;
typedef struct sockaddr zhang;
struct MSG_STRUCT
{
char msg[512] = "";
char User_Name[32] = "";
float File_Len = 0;
};struct IP_STRUCT
{
char IP[32] = "";
char buf[512] = "";
char User_Name[32] = "";
int id = 0;
int PORT = 0;
int ip[3];
int Cli_fd = 0;
int Ser_fd = 0;
bool is_ip = false;
bool connected = false;
};struct File_Data
{
char Path[512];char buf[FULL_LEN];
char File_Name[64];
bool success = false;
float size = 0;
};size_t GetFileSize(const char *Path)
{
FILE *READ = fopen(Path, "r");if (READ == NULL)
{
fclose(READ);
return -1;
}
else
{
fseek(READ, 0, SEEK_END);
int len = ftell(READ);
fclose(READ);
return len;
}
}void *Send_Data(void *ff, void *bu)
{
File_Data *r = (struct File_Data *)bu;int fd = *(int *)ff;
FILE *Path = fopen(r->Path, "r");
bzero(r->buf, sizeof(r->buf));
int n = 0;
while (n = fread(r->buf, sizeof(char), FULL_LEN, Path))
{
if (send(fd, r->buf, n, 0) < 0)
{
r->success = false;
break;
}bzero(r->buf, sizeof(r->buf));
}puts("成功发送");
close(fd);
r->success = true;
fclose(Path);
}void *Recv_Data(void *ff, void *bu)
{
File_Data *r = (struct File_Data *)bu;int fd = *(int *)ff;
std::string str = r->Path;
int offset = str.rfind("/");
str.erase(0, offset);
strcpy(r->File_Name, str.c_str());char *TempStr = new char[256];
sprintf(TempStr, "/sdcard/Server/%s", r->File_Name);
FILE *Path = fopen(TempStr, "w+");bzero(r->buf, sizeof(r->buf));
int n = 0, count = 0;
while (n = recv(fd, r->buf, FULL_LEN, 0))
{
if (n < 0)
break;if (fwrite(r->buf, sizeof(char), n, Path) < n)
{
printf("Failed!\n");
r->success = false;
break;
}
count += n;bzero(r->buf, sizeof(r->buf));
}printf("文件接收完毕,大小%fMB\n", (float)count / 1024.0 / 1024.0);
close(fd);
r->success = true;
fclose(Path);
free(TempStr);
istrans = false;
}void *User_thread(void *p)
{
int fd = *(int *)p;
while (true)
{
char buf[sizeof(MSG_STRUCT)];
if (recv(fd, buf, sizeof(buf), 0) > 0)
{
MSG_STRUCT Msg = *(struct MSG_STRUCT *)buf;
if (strcmp(Msg.msg, "INIT_OK") == 0)
{
send(fd, User_Name, sizeof(User_Name), 0);
}if (strcmp(Msg.msg, "FILE_TRANS") == 0)
{
printf("%s向你发了一个%fMB的文件,是否接收?\n", Msg.User_Name,
Msg.File_Len);
Again:
puts("请输入Y/N");
while (YN == 'O');
if (YN == 'Y')
{
YN = 'O';
send(fd, "Y", sizeof("N"), 0);
}
else if (YN == 'N')
{
YN = 'O';
send(fd, "N", sizeof("N"), 0);
break;
}
else
{
puts("错误选择!");
goto Again;
}char buff[512];
recv(fd, buff, sizeof(buff), 0);
File_Data temp;
strcpy(temp.Path, buff);
istrans = true;
Recv_Data((void *)&fd, (void *)&temp);
}
}
else {
close(fd);
break;
}
}
}void *Self_IP(void *IO)
{
IP_STRUCT *n = (struct IP_STRUCT *)IO;
FILE *P = popen("ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d 'addr:'","r");char IP[1024];
fread(IP, sizeof(char), sizeof(IP), P);
std::string str;
str = IP;
if (str[str.size() - 1] == '\n')
str.resize((str.size() - 1));
sprintf(n->IP, "%s", str.c_str());
char *Line = new char[256], *ptr;
strcpy(Line, str.c_str());
ptr = strtok(Line, ".");
int count = 0;
n->ip[count] = atoi(ptr);
while (ptr)
{
ptr = strtok(NULL, ".");
if (ptr)
{
count += 1;
n->ip[count] = atoi(ptr);
}}
char temp1[32];
char ip3[12];
sprintf(ip3, "%d", n->ip[3]);
std::string str1 = ip3;if (str1.size() > 2)
sprintf(temp1, "22%d", n->ip[3]);
else if (str1.size() <= 2)
sprintf(temp1, "222%d", n->ip[3]);n->PORT = atoi(temp1);
pclose(P);
free(Line);
}void *Server(void *p)
{
IP_STRUCT n = *(struct IP_STRUCT *)p;
n.Ser_fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in Saddr;
Saddr.sin_family = AF_INET;
Saddr.sin_port = htons(n.PORT);
Saddr.sin_addr.s_addr = htons(INADDR_ANY);if (bind(n.Ser_fd, (struct sockaddr *)&Saddr, sizeof(Saddr)) == -1)
perror("绑定失败");
if (listen(n.Ser_fd, 15) == -1)
perror("监听失败");
while (true)
{
struct sockaddr_in fromaddr;
socklen_t len = sizeof(fromaddr);
n.Cli_fd = accept(n.Ser_fd, (struct sockaddr *)&fromaddr, &len);pthread_t user;
pthread_create(&user, 0, User_thread, &n.Cli_fd);
//pthread_join(user, NULL);
}}
void *Client(void *ii)
{IP_STRUCT *ai = (struct IP_STRUCT *)ii;
ai->Cli_fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in Cliaddr;
Cliaddr.sin_family = AF_INET;
Cliaddr.sin_port = htons(0);
Cliaddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(ai->Cli_fd,(zhang *)&Cliaddr,sizeof(Cliaddr)))
perror("绑定失败");
struct sockaddr_in Seraddr;
Seraddr.sin_family = AF_INET;
Seraddr.sin_port = htons(ai->PORT);
Seraddr.sin_addr.s_addr = inet_addr(ai->IP);
if (connect(ai->Cli_fd, (zhang *) &Seraddr, sizeof(Seraddr)) < 0)
{
// perror("连接失败");
ai->connected = false;
}
else
ai->connected = true;}
void *ping(void *ii)
{
fd_set rset;
fd_set wset;IP_STRUCT *ai = (struct IP_STRUCT *)ii;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(ai->PORT);
addr.sin_addr.s_addr = inet_addr(ai->IP);int flag = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flag | O_NONBLOCK);
struct timeval tm;
tm.tv_sec = TIMEOUT;
tm.tv_usec = 0;if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(sockfd, &rset);
FD_SET(sockfd, &wset);
int error;
socklen_t len = sizeof(error);
if (select(sockfd + 1, &rset, &wset, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
if (error == 0)
ai->is_ip = true;
else
ai->is_ip = false;
}}
else
ai->is_ip = true;close(sockfd);
}IP_STRUCT Self;
IP_STRUCT native[15];
int uid = 0;
void *Up_Load(void *p);
void *Init(void *p);
void *ChangeN(void *p);void *Up_Load(void *p)
{
if (uid == 0)
puts("没有可配对用户");
else
{
int total = 0;
for (int i = 1; i <= uid; i++)
{
Client((void*)&native[i]);
if (native[i].connected == true) {
printf("用户名:%s, IP地址:%s, ID:%d\n", native[i].User_Name, native[i].IP,
native[i].id);
total += 1;
}
else
close(native[i].Cli_fd);
}
if (total > 0) {printf("请输入需要配对用户的ID\n输入: ");
int choose;
std::cin >> choose;
Again:
printf("请输入需要发送的文件绝对路径\n输入: ");
char choise[512];
std::cin >> choise;
if (access(choise, 0) == -1)
{
puts("路径错误,请重新输入!");
goto Again;
}
MSG_STRUCT Msg;
Msg.File_Len = (GetFileSize(choise)) / 1024.0f / 1024.0f;
sprintf(Msg.msg, "FILE_TRANS");
sprintf(Msg.User_Name, "%s", User_Name);
send(native[choose].Cli_fd, (void *)&Msg, sizeof(Msg), 0);
bzero(native[choose].buf, sizeof(native[choose].buf));
recv(native[choose].Cli_fd, native[choose].buf, sizeof(native[choose].buf), 0);
if (strcmp(native[choose].buf, "N") == 0)
{
std::cout << native[choose].User_Name << "拒绝接收你的文件!" << std::endl;
close(native[choose].Cli_fd);
}
else
{
send(native[choose].Cli_fd, choise, sizeof(choise), 0);
File_Data tempf;
tempf.size = (GetFileSize(choise)) / 1024.0f / 1024.0f;
strcpy(tempf.Path, choise);
Send_Data((void *)&native[choose].Cli_fd, (void *)&tempf);
}
}
else {
puts("没有可配对用户");
uid = 0;
}}
}
void *Init(void *p)
{
uid = 0;
memset(native, 0, sizeof(native));for (int aa = ipv4; aa < ipv4 + 13; aa++)
{
IP_STRUCT ip = *(struct IP_STRUCT *)p;if (aa == ip.ip[3])
continue;char buf[64];
sprintf(ip.IP, "%d.%d.%d.%d", ip.ip[0], ip.ip[1], ip.ip[2], aa);
char ip3[12],temp1[12];
sprintf(ip3, "%d", aa);
std::string str1 = ip3;if (str1.size() > 2)
sprintf(temp1, "22%d", aa);
else if (str1.size() <= 2)
sprintf(temp1, "222%d", aa);ip.PORT = atoi(temp1);
ping((void *)&ip);
if (ip.is_ip == true)
{
bzero(ip.buf, sizeof(ip.buf));
Client((void *)&ip);
if (ip.connected == true)
{
send(ip.Cli_fd, "INIT_OK", strlen("INIT_OK"), 0);
recv(ip.Cli_fd, ip.User_Name, sizeof(ip.User_Name), 0);
uid += 1;
ip.id = uid;
native[uid] = ip;
}
}}
if (uid != 0)
printf("局域网内共嗅探到%d名用户\n", uid);
else
printf("局域网内未曾嗅探到一名用户\n");
// pthread_exit(0);
}
void *Menu(void *p)
{while (true)
{
while (istrans == true);
puts("------------------------");puts("Zhang-局域网文件传输终端程序");
puts("(1) 局域网嗅探");
puts("(2) 传输文件");
puts("(3) 更改用户名");
puts("------------------------");
std::cout << "请输入你需要使用功能的序号: " << std::endl;
char choise[12];
std::cin >> choise;
if (atoi(choise) == 1)
Init((void *)&Self);
else if (atoi(choise) == 2)
Up_Load(NULL);
else if (atoi(choise) == 3)
ChangeN(NULL);
else if (strcmp(choise,"Y") == 0)
YN = 'Y';
else if (strcmp(choise,"N") == 0)
YN = 'N';
else puts("选择错误");
sleep(1);std::cout << std::endl << std::endl;
}
}void *ChangeN(void *p)
{
FILE *Name = fopen(CONFIG, "w+");
std::cout << "请输入用户名: ";
std::cin >> User_Name;
fprintf(Name, "%s", User_Name);
fclose(Name);
}int main()
{
if (access("/sdcard/Server/", 0) == -1)
system("mkdir /sdcard/Server/");if (access(CONFIG, 0) == -1)
{
ChangeN(NULL);
}
else
{
FILE *Name = fopen(CONFIG, "r+");
fscanf(Name, "%s", User_Name);
fclose(Name);
}Self_IP((void *)&Self);
char ip3[12];
sprintf(ip3, "%d", Self.ip[3]);
std::string str = ip3;if (str.size() > 1)
{
str.resize(str.size() - 1);
str += "0";
}
else if (str.size() == 1)
str = "0";ipv4 = atoi(str.c_str());
pthread_t Ser;
pthread_create(&Ser, NULL, Server, &Self);
pthread_t menu;
pthread_create(&menu, NULL, Menu, NULL);
for (;;);
}