主要解决的问题
做服务器的主机通常是不接显示器的,如果说路由器重启,或者服务器搬家,都会影响服务器ip重置,手动锁死ip只有特殊情况才会用,大多数都是跟随路由器分配的网段自动获取的;当然抓包也能实现,但这个做起来主要是针对不太爱折腾的同学;现成的程序我先放出来,想自己改的就拉到底部clone一下代码,其实很简单
app-debug.apk - 蓝奏云文件大小:3.8 M|https://wwb.lanzoub.com/iW87S05kke2h
为啥不搞现有的nas?
一开始我是想搞一个NAS的,但一个nas主机就好贵,而且配置还低,主机+硬盘得万把块钱;然后我搜了一下软路由,发现同样的价格我可以买一台性能匹配笔记本的小主机了,自建服务,硬盘可以自由拓展和挂载,可玩性更强;我就按步骤来说吧,先看一下我怎么配的(具体品牌不讲了,推荐试试那种无风扇的软路由)
(源码在底部,上传在github可直接取)
上面的就是我配的一个用作局域网共享的nas,其实也不是nas就是一个具备SMB服务的ubuntu而已
具体smb配置我这篇文章我不多说,可以看看我这一篇文章
1.正文
说到检索工具,主要是方便快速查找服务器用的
实现过程:服务器开机后,启动web服务,shell运行C++程序,对7171端口广播web路径;手机udp监听后,通过拼接得到该服务器内置的web页面
2.准备
1.在ubuntu安装apache服务,安装完在网站根目录建一个供设备扫描到后访问的页面(例如/udp/index.html)
2.安装g++,用于编译cpp文件,编译好后写一个shell脚本运行该C++程序,并设置开机启动
上面这个能理解的话可以自己尝试写出来,当然本篇文章也会粘贴部分核心代码,和给出源码链接
先通过一个视频看一下效果,我上传在csdn自带的视频里面,可以看一下
局域网的服务器检索工具-CSDN直播局域网的服务器检索工具https://live.csdn.net/v/212957?spm=1001.2014.3001.5501
3.主要代码:
下面这个是要在ubuntu当中编译的源文件,g++ udpServer.cpp -o udpServer,并且要通过shell脚本设置为开机启动,这个不赘述很简单
// 发送端
#include <iostream>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
using namespace std;
int main()
{
setvbuf(stdout, NULL, _IONBF, 0);
fflush(stdout);
int sock = -1;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
cout<<"socket error"<<endl;
return false;
}
const int opt = 1;
//设置该套接字为广播类型,
int nb = 0;
nb = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));
if(nb == -1)
{
cout<<"set socket error..."<<endl;
return false;
}
struct sockaddr_in addrto;
bzero(&addrto, sizeof(struct sockaddr_in));
addrto.sin_family=AF_INET;
addrto.sin_addr.s_addr=htonl(INADDR_BROADCAST);
addrto.sin_port=htons(7171);
int nlen=sizeof(addrto);
while(1)
{
sleep(10);
//从广播地址发送消息
char smsg[] = {"udp/index.html"};
int ret=sendto(sock, smsg, strlen(smsg), 0, (sockaddr*)&addrto, nlen);
if(ret<0)
{
cout<<"send error...."<<ret<<endl;
}
else
{
printf("send success\r\n");
}
}
return 0;
}
然后就是手机端的UDP核心部分,端口号对应上面C++里面的addrto.sin_port=htons(7171); 可以自定义
//扫描本地信息
private void receiveMessage(int phonePort) {
if(phonePort==0){
Toast.makeText(MainActivity.this,"端口号获取失败",Toast.LENGTH_LONG).show();
}
Log.e("receiveMessage", "开始扫描本地"+phonePort);
messageTemp = null;
//开一个子线程扫描本地,扫描到了,线程就自己关闭了
new Thread() {
public void run() {
try {
//会有端口占用的问题,这样写就不会有什么问题了
if (udpSocket == null) {
udpSocket = new DatagramSocket(null);
udpSocket.setReuseAddress(true);
udpSocket.bind(new InetSocketAddress(phonePort));//接收者地址
}
} catch (SocketException e) {
Log.e("SocketException-1", e.toString());
//做一下异常处理
}
while (!stopReceiver) {
Log.e("info:", "进入循环");
byte[] receBuf = new byte[1024];
packet = new DatagramPacket(receBuf, receBuf.length);//UDP套接字
try {
udpSocket.receive(packet);//blocked here
} catch (IOException e) {
e.printStackTrace();
}
String address = String.valueOf(packet.getAddress());
String path = null;
try {
path = new String(packet.getData(), 0, packet.getLength(), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//Log.e("address", address);
if (!address.contains("null") && messageTemp == null) {//这个是去一下重,防止拿到udp数据重复
//下面这些调试没有出现问题
messageTemp = address;
if (messageTemp.contains("/")) {
LocalAddress = messageTemp.replace("/", "");
} else {
LocalAddress = messageTemp;
}
Log.e("udp::", LocalAddress+path);
String finalPath = path;
runOnUiThread(new Runnable() {
@Override
public void run() {
radarView.stop();
DetailDialog(LocalAddress,"http://"+LocalAddress +"/"+ finalPath);
}
});
//没有问题后操作完成
if (socketClosed()) {
return;//退出该方法
}
}
}
Log.e("info:", "出了循环");
}
}.start();
}
private boolean socketClosed() {
try {
if (udpSocket != null) {
System.out.println("内部断开socket");
if (!udpSocket.isClosed()) {
udpSocket.close();
}
udpSocket.disconnect();
udpSocket = null;
return true;
} else {
return true;
}
}catch(Exception e){
udpSocket = null;
return true;
}
}
到这里其实差不多就结束了
完整源码在这边~感兴趣的麻烦各位star一下,感激不尽GitHub - YangWenlong71/udpClientContribute to YangWenlong71/udpClient development by creating an account on GitHub.https://github.com/YangWenlong71/udpClient