公司要求搞个手机控制电视盒子的功能,涉及到文件传输和控制指令,网上有很多例子,简单的总结一下,使用一个socket线程来进行文件传输和指令传输
server端WifiFileServers.java
public class WifiFileServers {
private ServerSocket serverSocket = null;
private String serversIp;
private Handler mHandler;
private HandlerThread handlerThread;
private Socket socket = null;
private OnServersListener serversListener;
public WifiFileServers(final int port){
handlerThread = new HandlerThread("WifiFileServers");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
//开启socket
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
serversIp = GetIpAddress.getLocalIpAddress();
}
});
}
public void startServers(final OnServersListener listener){
serversListener = listener;
mHandler.post(new Runnable() {
@Override
public void run() {
int port = serverSocket.getLocalPort();
serversListener.onServersIp(serversIp,port);
//等待连接,我这里做的是单连接,多连接可以建个连接类,把socket放到连接类中
while (!serverSocket.isClosed()){
try {
socket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
//连接成功开始接收数据,如果多连接需要多开线程
if(socket != null){
start();
}
}
}
});
}
public void start() {
int port = serverSocket.getLocalPort();
String ip = socket.getInetAddress().getHostAddress();
serversListener.onConnect(port,ip);
long length = 0;
int len;
FileOutputStream fos = null;
File file = null;
//用于接收文件数据
byte[] bytes = new byte[8192];
//用于接收字符串
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
File path = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video");
if(!path.exists()){
path.mkdir();
}
int type = -1;
String fileName = null;
long size = 0;
//等待数据
while ((len = socket.getInputStream().read(bytes)) != -1) {
//数据长度为1的时候,可能为client端发来的数据类型标签
if(len == 1){
//0表示准备发送字符串
if(bytes[0] == '0' && type == -1){
type = 1;
//准备好接收字符串
socket.getOutputStream().write('0');
}else if(bytes[0] == '\0' && type == 1){//表示字符串接收完成
//转成字符串
String data = new String(baos.toByteArray(),"utf8");
baos.flush();
baos.close();
baos.reset();
//开始解析
String t = data.substring(0,1);
if("0".equals(t)){
fileName = data.substring(1,data.length());
}else if("1".equals(t)){
length = Long.valueOf(data.substring(1,data.length()));
}else if("3".equals(t)){//正常字符串
serversListener.onReceive(port,ip,data.substring(1,data.length()));
}
type = -1;
//通知client字符串接收完成
socket.getOutputStream().write('1');
}else if(bytes[0] == '5' && type == -1){//准备接收文件
type = 0;
size = 0;
//创建文件
if(fileName != null){
file = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video", fileName);
if (file.exists()) {
file.delete();
}
fos = new FileOutputStream(file);
}
//通知client端准备接收数据
socket.getOutputStream().write('5');
}else if(type == 0 && fos != null) {//接收只有1的数据
fos.write(bytes, 0, len);
fos.flush();
size += len;
serversListener.onData(port,ip,fileName,length,size);
//接收到的数据和文件大小相等
if(size == length){
//接收完成,通知client端
type = -1;
fos.close();
socket.getOutputStream().write('9');
serversListener.onOver(port,ip,fileName);
fileName = null;
}
}else if(type == 1){//字符串最后1位数据
baos.write(bytes,0,len);
}
}else{
if(type == 1){
if(bytes[len -1] == '\0'){//字符串最后1位是\0,表示字符串接收结束
baos.write(bytes,0,len -1);
String data = new String(baos.toByteArray(),"utf8");
baos.flush();
baos.close();
baos.reset();
String t = data.substring(0,1);
if("0".equals(t)){
fileName = data.substring(1,data.length());
}else if("1".equals(t)){
length = Long.valueOf(data.substring(1,data.length()));
}else if("3".equals(t)){
serversListener.onReceive(port,ip,data.substring(1,data.length()));
}
type = -1;
socket.getOutputStream().write('1');
}else{
//正常接收
baos.write(bytes,0,len);
}
}else if(type == 0 && fos != null){
fos.write(bytes, 0, len);
fos.flush();
size += len;
serversListener.onData(port,ip,fileName,length,size);
if(size == length){
type = -1;
fos.close();
socket.getOutputStream().write('9');
serversListener.onOver(port,ip,fileName);
fileName = null;
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
serversListener.onDisconnect(port,ip);
try {
socket.getInputStream().close();
socket.getOutputStream().close();
socket.close();
if(fos != null){
fos.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public void release(){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
handlerThread.quit();
}
interface OnServersListener{
void onServersIp(String serversIp,int port);
void onConnect(int port,String clientIp);
void onData(int port,String clientIp,String fileName,long size,long progress);
void onReceive(int port, String clientIp, String data);
void onOver(int port, String clientIp,String fileName);
void onDisconnect(int port,String clientIp);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView editText_1;
private TextView editText_2;
private EditText editText_data;
private WifiFileServers wifiFileServers;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_1 = findViewById(R.id.et_1);
editText_2 = findViewById(R.id.et_2);
editText_data = findViewById(R.id.et_data);
//创建文件夹
File file = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video");
if(file.exists()){
file.mkdir();
}
receiveData();
}
public void send(View view){
}
public void receiveData(){
//初始化
wifiFileServers = new WifiFileServers(8068);
//开启server线程
wifiFileServers.startServers(fileListener);
}
//释放socket资源
@Override
public void onBackPressed() {
super.onBackPressed();
wifiFileServers.release();
}
//回调
WifiFileServers.OnServersListener fileListener = new WifiFileServers.OnServersListener() {
@Override
public void onServersIp(final String serversIp, final int port) {
runOnUiThread(new Runnable() {
@Override
public void run() {
editText_1.setText("IP:" + serversIp + " PORT: " + port);
}
});
}
@Override
public void onConnect(int port, final String clientIp) {
runOnUiThread(new Runnable() {
@Override
public void run() {
editText_1.setText(clientIp+"连接成功");
}
});
}
@Override
public void onData(int port, String clientIp, final String fileName, final long size, final long progress) {
runOnUiThread(new Runnable() {
@Override
public void run() {
long p = progress*100/size;
editText_2.setText(fileName+p+"%");
}
});
}
@Override
public void onReceive(int port, String clientIp, String data) {
}
@Override
public void onOver(int port, String clientIp, String fileName) {
}
@Override
public void onDisconnect(int port, final String clientIp) {
runOnUiThread(new Runnable() {
@Override
public void run() {
editText_1.setText(clientIp+"断开连接");
}
});
}
};
}
布局就不贴了
client端ClientFileServers.java
public class ClientFileServers {
private Socket socket = null;
private OutputStream outputStream = null;
private InputStream inputStream = null;
private OnServersListener serversListener;
private Handler mHandler;
private HandlerThread handlerThread;
private int port;
public ClientFileServers() {
handlerThread = new HandlerThread("ClientFileServers");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
}
//连接
public void connect(final String ip, final int port, OnServersListener listener) {
serversListener = listener;
this.port = port;
mHandler.post(new Runnable() {
@Override
public void run() {
try {
socket = new Socket(ip, port);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
serversListener.onConnect(port);
} catch (IOException e) {
e.printStackTrace();
serversListener.onError(port, -1);
}
}
});
}
private boolean sendString(String data) throws IOException{
byte[] buffer = new byte[8192];
//先发送个0给server端,0表示接下来要发送字符串数据
outputStream.write('0');
//接收server端的反馈,0表示准备完成
if(inputStream.read(buffer) != -1){
if(buffer[0] != '0'){
return false;
}
}
//发送数据
byte[] b = data.getBytes("utf8");
outputStream.write(b,0,b.length);
//'\0'表示字符串结束
outputStream.write('\0');
//接收server反馈,1表示接收成功
if(inputStream.read(buffer) != -1){
if(buffer[0] != '1'){
return false;
}
}
return true;
}
//发生文字
public void sendData(final String data){
mHandler.post(new Runnable() {
@Override
public void run() {
try {
if(!sendString(data)){
serversListener.onError(port,3);
return;
}
serversListener.onSendData(port);
} catch (IOException e) {
e.printStackTrace();
synchronized (ClientFileServers.this){
try {
if(outputStream != null){
outputStream.close();
outputStream = null;
}
if(inputStream != null){
inputStream.close();
inputStream = null;
}
if(socket != null){
socket.close();
socket = null;
serversListener.onDisconnect(port);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
});
}
//发送文件
public void sendFile(final File file) {
mHandler.post(new Runnable() {
@Override
public void run() {
FileInputStream fis = null;
try {
//先发送文件名,在文件名前加个0表示这段数据是文件名,也可用json格式,看自己写法
String path = "0"+file.getName();
//通过发送字符串的形式发送
if(!sendString(path)){
serversListener.onError(port,3);
return;
}
//再发送文件大小,1表示文件长度
String l = "1"+file.length();
if(!sendString(l)){
serversListener.onError(port,3);
return;
}
//5表示告诉server要开始发送文件数据
byte[] b = new byte[8192]; // 8k
outputStream.write('5');
//server反馈5表示server准备好接收
if(inputStream.read(b) != -1){
if(b[0] != '5'){
serversListener.onError(port,3);
return ;
}
}
//发送文件数据
fis = new FileInputStream(file);
long size = 0;
byte[] buffer = new byte[8192]; // 8k
int len;
while ((len = fis.read(buffer)) != -1) {
size += len;
outputStream.write(buffer, 0, len);
outputStream.flush();
serversListener.onSendFile(port,file.length(),size);
}
//等待server端反馈,9表示接收成功
if(inputStream.read(b) != -1){
if(b[0] != '9'){
serversListener.onError(port,3);
return ;
}
}
serversListener.onReceive(port);
} catch (IOException e) {
e.printStackTrace();
synchronized (ClientFileServers.this){
try {
if(outputStream != null){
outputStream.close();
outputStream = null;
}
if(inputStream != null){
inputStream.close();
inputStream = null;
}
if(socket != null){
socket.close();
socket = null;
serversListener.onDisconnect(port);
}
if(fis != null){
fis.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
});
}
public void release() {
synchronized (ClientFileServers.this){
try {
if(inputStream != null){
inputStream.close();
inputStream = null;
}
if (outputStream != null) {
outputStream.close();
outputStream = null;
}
if (socket != null) {
socket.close();
socket = null;
serversListener.onDisconnect(port);
}
} catch (IOException e) {
e.printStackTrace();
}
}
handlerThread.quit();
}
interface OnServersListener {
void onConnect(int port);
void onSendData(int port);
void onSendFile(int port,long size,long progress);
void onReceive(int port);
void onDisconnect(int port);
void onError(int port, int error);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private String[] denied;
private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
private EditText editText_data;
private TextView editText_ip;
private TextView editText_receive;
private String ip = "192.168.1.38";
private String fileName = "1520564093079.mp4";
// 1520583417803 1520564093079 1521533868730 1528278027688 1528363714863
private ClientFileServers fileServers;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_ip = findViewById(R.id.et_ip);
editText_data = findViewById(R.id.et_data);
editText_receive = findViewById(R.id.et_receive);
editText_ip.setText(ip);
//权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < permissions.length; i++) {
if (PermissionChecker.checkSelfPermission(this, permissions[i]) == PackageManager.PERMISSION_DENIED) {
list.add(permissions[i]);
}
}
if (list.size() != 0) {
denied = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
denied[i] = list.get(i);
ActivityCompat.requestPermissions(this, denied, 5);
}
} else {
init();
}
} else {
init();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 5) {
boolean isDenied = false;
for (int i = 0; i < denied.length; i++) {
String permission = denied[i];
for (int j = 0; j < permissions.length; j++) {
if (permissions[j].equals(permission)) {
if (grantResults[j] != PackageManager.PERMISSION_GRANTED) {
isDenied = true;
break;
}
}
}
}
if (isDenied) {
Toast.makeText(this, "请开启权限", Toast.LENGTH_SHORT).show();
} else {
init();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
private void init(){
//初始化socket
fileServers = new ClientFileServers();
}
public void connect(View view){
//连接server端
fileServers.connect(ip,8068,serversListener);
}
public void send(View view){
//发送文件
String f = Environment.getExternalStorageDirectory()+"/HMSDK/video/"+fileName;
File file = new File(f);
fileServers.sendFile(file);
}
//当客户端界面返回时,关闭相应的socket资源
@Override
public void onBackPressed() {
super.onBackPressed();
fileServers.release();
}
//回调
private ClientFileServers.OnServersListener serversListener = new ClientFileServers.OnServersListener() {
@Override
public void onConnect(int port) {
runOnUiThread(new Runnable() {
@Override
public void run() {
editText_ip.setText(ip+"连接成功");
}
});
}
@Override
public void onSendData(int port) {
}
@Override
public void onSendFile(int port, final long size, final long progress) {
runOnUiThread(new Runnable() {
@Override
public void run() {
long p = progress*100/size;
editText_receive.setText(fileName+p+"%");
}
});
}
@Override
public void onReceive(int port) {
runOnUiThread(new Runnable() {
@Override
public void run() {
editText_receive.setText("文件接收成功");
}
});
}
@Override
public void onDisconnect(int port) {
}
@Override
public void onError(int port, int error) {
}
};
}