吉林省建设通官方网站建设一个外贸网站需要多少钱

当前位置: 首页 > news >正文

吉林省建设通官方网站,建设一个外贸网站需要多少钱,做百度手机网站优化点,网站建设哪家go好本节主要通过实战来了解Socket在TCP/IP协议中充当的是一个什么角色#xff0c;有什么作用。通过Socket使用TCP协议实现局域网内手机A充当服务端#xff0c;手机B充当客户端#xff0c;手机B连接手机A#xff0c;手机A获取屏幕数据转化为Bitmap#xff0c;通过Socket传递个…本节主要通过实战来了解Socket在TCP/IP协议中充当的是一个什么角色有什么作用。通过Socket使用TCP协议实现局域网内手机A充当服务端手机B充当客户端手机B连接手机A手机A获取屏幕数据转化为Bitmap通过Socket传递个手机B显示。 实现效果 一、 Socket是什么 Socket是应用层与TCP/IP协议族通信的中间软件抽象层它是一组接口。在设计模式中Socket其实就是一个门面模式它把复杂的TCP/IP协议族隐藏在Socket接口后面对用户来说一组简单的接口就是全部让Socket去组织数据以符合指定的协议。 主机 A 的应用程序要能和主机 B 的应用程序通信必须通过 Socket 建立连接而建立 Socket 连接必须需要底层TCP/IP 协议来建立 TCP 连接。建立 TCP 连接需要底层 IP 协议来寻址网络中的主机。我们知道网络层使用的 IP 协议可以帮助我们根据 IP 地址来找到目标主机但是一台主机上可能运行着多个应用程序如何才能与指定的应用程序通信就要通过 TCP 或 UPD 的地址也就是端口号来指定。这样就可以通过一个 Socket 实例唯一代表一个主机上的一个应用程序的通信链路了。  短连接连接-传输数据-关闭连接 传统HTTP是无状态的浏览器和服务器每进行一次HTTP操作就建立一次连接但任务结束就中断连接。也可以这样说短连接是指SOCKET连接后发送后接收完数据后马上断开连接。 长连接连接-传输数据-保持连接 - 传输数据- …… -关闭连接 长连接指建立SOCKET连接后不管是否使用都保持连接。 什么时候用长连接短连接 长连接多用于操作频繁点对点的通讯而且连接数不能太多情况。每个TCP连接都需要三步握手这需要时间如果每个操作都是先连接再操作的话那么处理速度会降低很多所以每个操作完后都不断开下次处理时直接发送数据包就OK了不用建立TCP连接。例如数据库的连接用长连接 如果用短连接频繁的通信会造成socket错误而且频繁的socket 创建也是对资源的浪费。 而像WEB网站的http服务一般都用短链接因为长连接对于服务端来说会耗费一定的资源而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源。 总之长连接和短连接的选择要视情况而定。 而我们接下来要实现的手机实时投屏效果使用的就是长连接。 二、Socket的使用 在使用Socket时我们会使用到ServiceSocket和SocketServerSocket负责绑定IP地址启动监听端口Socket负责发起连接操作。连接成功后双方通过输入和输出流进行同步阻塞式通信。 1、创建TcpServerRunnable TCP服务端 1由于Android在使用网络通讯时要放在子线程中执行所以可以将TcpServerRunnable实现Runnable接口。 public class TcpServerRunnable implements Runnable {Overridepublic void run() {} } 2在执行run方法里面创建ServiceSocketServerSocket内部使用的是TCP协议如果想要使用UDP协议可以使用DatagramSocket。 private boolean ServerCreate() {try {serverSocket new ServerSocket(port, 1);} catch (Exception e) {e.printStackTrace();if (listener ! null) {listener.onServerClose();}return false;}return true; } 3创建成功后开启 while 循环监听TCP服务端是否被客户端连接 private void ServerRun() {if (!ServerCreate()) {return;}while (true) {if (!ServerListen()) {break;}} }private boolean ServerListen() {try {socket serverSocket.accept();} catch (Exception e) {e.printStackTrace();return false;}if (listener ! null) {listener.onServerConnect();}return true; } 4当有客户端连接到服务端时开启 while 循环从内存中拿取bitmap屏幕数据组装协议数据发送给客户端。 private void ServerRun() {if (!ServerCreate()) {return;}while (true) {if (!ServerListen()) {break;}while (ServerIsConnect()) {ServerTransmitBitmap();ServerSleep(10);}} }private final static byte[] PACKAGE_HEAD {(byte) 0xFF, (byte) 0xCF, (byte) 0xFA, (byte) 0xBF, (byte) 0xF6, (byte) 0xAF, (byte) 0xFE, (byte) 0xFF};/*** 写入 协议头投屏bitmap数据/ private void ServerTransmitBitmap() {try {DataOutputStream dataOutputStream new DataOutputStream(socket.getOutputStream());if (bitmap ! null) {byte[] bytes MyUtils.BitmaptoBytes(bitmap);dataOutputStream.write(PACKAGE_HEAD);dataOutputStream.writeInt(MyUtils.getScreenWidth());dataOutputStream.writeInt(MyUtils.getScreenHeight());dataOutputStream.writeInt(bytes.length);dataOutputStream.write(bytes);}dataOutputStream.flush();} catch (IOException e) {e.printStackTrace();} } 当执行到dataOutputStream.flush();时就会将数据发送给客户端由于ServerTransmitBitmap()方法是在 while 循环里面的所以当手机屏幕数据刷新后重新赋值给bitmap服务端会自动将新的bitmap再次组装发送给客户端实现投屏实时刷新的效果。 public class TcpServerRunnable implements Runnable {private static final String TAG TcpServerRunnable;private ServerSocket serverSocket;private Socket socket;private int port;private Bitmap bitmap;public void setPort(int port) {this.port port;}public void setBitmap(Bitmap bitmap) {this.bitmap bitmap;}Overridepublic void run() {ServerRun();}/** 运行服务端/private void ServerRun() {if (!ServerCreate()) {return;}while (true) {if (!ServerListen()) {break;}while (ServerIsConnect()) {ServerTransmitBitmap();ServerSleep(10);}}}/** 使用ServerSocket创建TCP服务端** return/private boolean ServerCreate() {try {serverSocket new ServerSocket(port, 1);} catch (Exception e) {e.printStackTrace();if (listener ! null) {listener.onServerClose();}return false;}return true;}/** 循环监听服务端是否被连接** return/private boolean ServerListen() {try {socket serverSocket.accept();} catch (Exception e) {e.printStackTrace();return false;}if (listener ! null) {listener.onServerConnect();}return true;}/** 判断服务端是否被连接** return/private boolean ServerIsConnect() {return socket ! null !socket.isClosed() socket.isConnected();}private final static byte[] PACKAGE_HEAD {(byte) 0xFF, (byte) 0xCF, (byte) 0xFA, (byte) 0xBF, (byte) 0xF6, (byte) 0xAF, (byte) 0xFE, (byte) 0xFF};/** 写入 协议头投屏bitmap数据/private void ServerTransmitBitmap() {try {DataOutputStream dataOutputStream new DataOutputStream(socket.getOutputStream());if (bitmap ! null) {byte[] bytes MyUtils.BitmaptoBytes(bitmap);dataOutputStream.write(PACKAGE_HEAD);dataOutputStream.writeInt(MyUtils.getScreenWidth());dataOutputStream.writeInt(MyUtils.getScreenHeight());dataOutputStream.writeInt(bytes.length);dataOutputStream.write(bytes);}dataOutputStream.flush();} catch (IOException e) {e.printStackTrace();}}private void ServerSleep(long millis) {try {Thread.sleep(millis);} catch (InterruptedException e) {e.printStackTrace();}}/** 关闭连接*/public void close() {ServerClose();}private void ServerClose() {try {if (socket ! null) {socket.close();serverSocket.close();}} catch (Exception e) {e.printStackTrace();}if (listener ! null) {listener.onServerClose();}}private ServerListener listener;public void setListener(ServerListener listener) {this.listener listener;}public interface ServerListener {void onServerConnect();void onServerClose();} } 2、获取手机屏幕数据并转化为bitmap 1创建ScreenCaptureService前台服务执行处理捕获设备屏幕的单例类ScreenCapture。 public class ScreenCaptureService extends Service {private ScreenCapture screenCapture;public ScreenCaptureService() {}Overridepublic int onStartCommand(Intent intent, int flags, int startId) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) {createNotificationChannel(); //创建通知栏你正在录屏}Bundle bundle intent.getExtras();if (bundle ! null) {int resultCode bundle.getInt(resultCode);Intent data bundle.getParcelable(resultData);screenCapture ScreenCapture.getInstance(this, resultCode, data);}screenCapture.startScreenCapture();return START_STICKY;}Overridepublic void onDestroy() {super.onDestroy();screenCapture.stopScreenCapture();}private void createNotificationChannel() {} } 2创建MediaProjection捕获设备屏幕上的内容并将数据转化为BitmapMyUtils.setBitmap(bitmap) 存储到静态变量中。 public class ScreenCapture implements ImageReader.OnImageAvailableListener{private static final String TAG ScreenCapture;private final MediaProjection mMediaProjection; // 用于捕获设备屏幕上的内容并进行录制或截图private VirtualDisplay mVirtualDisplay;private final ImageReader mImageReader;private final int screen_width;private final int screen_height;private final int screen_density;private static volatile ScreenCapture screenCapture;SuppressLint(WrongConstant)private ScreenCapture(Context context, int resultCode, Intent data) {MediaProjectionManager mMediaProjectionManager (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);mMediaProjection mMediaProjectionManager.getMediaProjection(resultCode, data);screen_width MyUtils.getScreenWidth();screen_height MyUtils.getScreenHeight();screen_density MyUtils.getScreenDensity();mImageReader ImageReader.newInstance(screen_width,screen_height,PixelFormat.RGBA_8888,2);}public static ScreenCapture getInstance(Context context, int resultCode, Intent data) {if(screenCapture null) {synchronized (ScreenCapture.class) {if(screenCapture null) {screenCapture new ScreenCapture(context, resultCode, data);}}}return screenCapture;}public void startScreenCapture() {if (mMediaProjection ! null) {setUpVirtualDisplay();}}private void setUpVirtualDisplay() {mVirtualDisplay mMediaProjection.createVirtualDisplay(ScreenCapture,screen_width,screen_height,screen_density,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(),null,null);mImageReader.setOnImageAvailableListener(this, null);}public void stopScreenCapture() {if (mVirtualDisplay ! null) {mVirtualDisplay.release();}}Overridepublic void onImageAvailable(ImageReader imageReader) {try {Image image imageReader.acquireLatestImage();if(image ! null) {Image.Plane[] planes image.getPlanes();ByteBuffer buffer planes[0].getBuffer();int pixelStride planes[0].getPixelStride();int rowStride planes[0].getRowStride();int rowPadding rowStride - pixelStride * screen_width;Bitmap bitmap Bitmap.createBitmap(screen_width rowPadding / pixelStride, screen_height, Bitmap.Config.ARGB_8888);bitmap.copyPixelsFromBuffer(buffer);MyUtils.setBitmap(bitmap);image.close();}} catch (Exception e) {e.printStackTrace();}} } 3、对获取的屏幕Bitmap进行压缩降低Bitmap大小加快Socket传输速度。非必须不压缩也行。创建BitmapProcessRunnable实现Runnable接口在子线程执行bitmap压缩操作。 public class BitmapProcessRunnable implements Runnable {private static final String TAG BitmapProcessRunnable;private boolean isRun false;public void setRun(boolean isRun) {this.isRun isRun;}Overridepublic void run() {while (isRun) {try {Bitmap bitmap MyUtils.getBitmap();Log.i(TAG, bitmap: bitmap);if (bitmap ! null) {bitmap MyUtils.BitmapMatrixCompress(bitmap);if (listener ! null) {listener.onProcessBitmap(bitmap);}}Thread.sleep(10);} catch (Exception e) {e.printStackTrace();}}}private ProcessListener listener;public interface ProcessListener {void onProcessBitmap(Bitmap bitmap);}public void setListener(ProcessListener listener) {this.listener listener;} } public static Bitmap BitmapMatrixCompress(Bitmap bitmap) {Matrix matrix new Matrix();matrix.setScale(0.5f, 0.5f);return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } 3、关联TCP客户端ServerFragment页面 1在ServerFragment页面创建TcpServerRunnableTCP服务端和BitmapProcessRunnable图片处理线程当用户点击创建按钮时调用MyUtils.ExecuteRunnable(tcpServerRunnable)执行TcpServerRunnable的run方法。 2客户端连接TCP服务端后在回调接口onServerConnect()里面开启前台服务ScreenCaptureService捕获屏幕数据同时执行BitmapProcessRunnable的run方法对获取到的bitmap进行压缩压缩完成将新bitmap赋值给TcpServerRunnableTCP服务端。 3TcpServerRunnableTCP服务端的 while 循环里面读取到新的bitmap进行组装bitmap协议数据发送给客户端。 public class ServerFragment extends Fragment implements View.OnClickListener {private static final String TAG ServerFragment;private static boolean server_create false;private TextView server_text;private Button create_button;private TcpServerRunnable tcpServerRunnable; // TCP服务端private BitmapProcessRunnable bitmapProcessRunnable; // 图片处理线程Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_server, container, false);}Overridepublic void onViewCreated(NonNull NotNull View view, Nullable org.jetbrains.annotations.Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);server_text view.findViewById(R.id.server_text);server_text.setText(MyUtils.getLocalAddress());create_button view.findViewById(R.id.create_button);create_button.setOnClickListener(this);bitmapProcessRunnable new BitmapProcessRunnable();bitmapProcessRunnable.setListener(bitmapProcessListener);tcpServerRunnable new TcpServerRunnable();tcpServerRunnable.setPort(MyUtils.tcpSocketPort);tcpServerRunnable.setListener(tcpServerListener);}Overridepublic void onClick(View view) {if (view.getId() R.id.create_button) {if (!server_create) {server_create true;MyUtils.ExecuteRunnable(tcpServerRunnable);create_button.setText(关闭);} else {server_create false;tcpServerRunnable.close();create_button.setText(创建);}}}Overridepublic void onDestroy() {super.onDestroy();tcpServerRunnable.close();}TcpServerRunnable.ServerListener tcpServerListener new TcpServerRunnable.ServerListener() {Overridepublic void onServerConnect() {bitmapProcessRunnable.setRun(true);// 压缩图片MyUtils.ExecuteRunnable(bitmapProcessRunnable);Bundle bundle new Bundle();Intent start new Intent(getActivity(), ScreenCaptureService.class);bundle.putInt(resultCode, MyUtils.getResultCode());bundle.putParcelable(resultData, MyUtils.getResultData());start.putExtras(bundle);// 启动投屏服务if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) {getActivity().startForegroundService(start);} else {getActivity().startService(start);}}Overridepublic void onServerClose() {bitmapProcessRunnable.setRun(false);Intent stop new Intent(getActivity(), ScreenCaptureService.class);getActivity().stopService(stop);}};BitmapProcessRunnable.ProcessListener bitmapProcessListener new BitmapProcessRunnable.ProcessListener() {Overridepublic void onProcessBitmap(Bitmap bitmap) {// 将压缩后的图片传给tcpServertcpServer发送给客户端tcpServerRunnable.setBitmap(bitmap);}}; } 4、创建TcpClientRunnable TCP客户端 1同样在子线程中开启连接TCP服务端这里需要知道服务端的IP地址和端口号。 Override public void run() {ClientRun(); }private void ClientRun() {if (!ClientConnect()) {return;} }private boolean ClientConnect() {try {socket new Socket(ip, port);} catch (Exception e) {e.printStackTrace();return false;}if (listener ! null) {listener.onClientConnect();}return true; } 2连接成功后开启 while 循环接收服务端发送过来的bitmap数据赋值给静态变量MyUtils.setBitmap()。 private void ClientRun() {if (!ClientConnect()) {return;}while (true) {while (ClientIsConnect()) {ClientReceiveBitmap();ClientSleep(10);}} }private void ClientReceiveBitmap() {try {Log.i(TAG,循环读取服务端传过来的投屏Bitmap);InputStream inputStream socket.getInputStream();boolean isHead true;for (byte b : PACKAGE_HEAD) {byte head (byte) inputStream.read();if (head ! b) {isHead false;break;}}if (isHead) {DataInputStream dataInputStream new DataInputStream(inputStream);int width dataInputStream.readInt();int height dataInputStream.readInt();int len dataInputStream.readInt();byte[] bytes new byte[len];dataInputStream.readFully(bytes, 0, len);Bitmap bitmap MyUtils.BytestoBitmap(bytes);if (bitmap ! null width ! 0 height ! 0) {if (listener ! null) {listener.onClientReceiveBitmap(bitmap, width, height);}}}} catch (Exception e) {e.printStackTrace();} } 5、客户端创建显示投屏的DisplayActivity 1DisplayActivity通过自定义DisplayView来实时显示投屏数据 public class DisplayActivity extends AppCompatActivity {private static final String TAG DisplayActivity;private DisplayView displayView;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_display);initView();}private void initView() {getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);displayView findViewById(R.id.displayView);displayView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {Overridepublic void onGlobalLayout() {displayView.setViewWidth(displayView.getWidth());displayView.setViewHeight(displayView.getHeight());displayView.getViewTreeObserver().removeOnGlobalLayoutListener(this);}});}} 2DisplayView继承自SurfaceView并实现Runnable接口当DisplayView添加到Activity后Surface第一次被创建时回调到void surfaceCreated()然后在surfaceCreated方法里面启动自己的run方法循环的将bitmap绘制到页面上。 public class DisplayView extends SurfaceView implements SurfaceHolder.Callback, Runnable{private static final String TAG DisplayView;private int viewWidth;private int viewHeight;private Bitmap bitmap;private int width;private int height;private SurfaceHolder surfaceHolder;private boolean isDraw false;public DisplayView(Context context) {super(context);initView();}public DisplayView(Context context, AttributeSet attrs) {super(context, attrs);initView();}public DisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}private void initView() {surfaceHolder getHolder();surfaceHolder.addCallback(this);surfaceHolder.setFormat(PixelFormat.TRANSLUCENT);setZOrderMediaOverlay(true);}Overridepublic void surfaceCreated(NonNull SurfaceHolder holder) {isDraw true;MyUtils.ExecuteRunnable(this);}Overridepublic void surfaceChanged(NonNull SurfaceHolder holder, int format, int width, int height) {}Overridepublic void surfaceDestroyed(NonNull SurfaceHolder holder) {isDraw false;}Overridepublic void run() {while (isDraw) {try {drawBitmap();Thread.sleep(10);} catch (Exception e) {e.printStackTrace();}}}public void drawBitmap() {Canvas canvas surfaceHolder.lockCanvas();if (canvas ! null) {bitmap getBitmap();if (bitmap ! null) {canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);Rect rect new Rect(0, 0, viewWidth, viewHeight);canvas.drawBitmap(bitmap, null, rect, null);}surfaceHolder.unlockCanvasAndPost(canvas);}}public Bitmap getBitmap() {// return bitmap;return MyUtils.getShowBitmap();}public void setBitmap(Bitmap bitmap, int width, int height) {this.bitmap bitmap;this.width width;this.height height;}public void setViewWidth(int width) {this.viewWidth width;}public void setViewHeight(int height) {this.viewHeight height;} }6、关联TCP客户端ClientFragment页面 1在ClientFragment页面创建TcpClientRunnableTCP客户端端当用户输入服务端IP地址点击连接按钮时调用MyUtils.ExecuteRunnable(tcpClientRunnable)执行TcpClientRunnable的run方法。 2客户端连接TCP服务端后在回调接口onClientConnect()里面开启DisplayActivityDisplayView创建等待bitmap写入MyUtils.setBitmap循环的将bitmap绘制到页面上。 3当客户端接收到服务端发送过来的投屏bitmap时回调到onClientReceiveBitmap()将bitmap设置到静态变量里面MyUtils.setBitmap(bitmap, width, height)。 public class ClientFragment extends Fragment implements View.OnClickListener {private static final String TAG ClientFragment;private static boolean client_connect false;private TextView client_edit;private Button connect_button;private TcpClientRunnable tcpClientRunnable;Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_client, container, false);}Overridepublic void onViewCreated(NonNull NotNull View view, Nullable org.jetbrains.annotations.Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);client_edit view.findViewById(R.id.client_edit);client_edit.setText(MyUtils.getLocalIp());connect_button view.findViewById(R.id.connect_button);connect_button.setOnClickListener(this);tcpClientRunnable new TcpClientRunnable();tcpClientRunnable.setPort(MyUtils.tcpSocketPort);tcpClientRunnable.setListener(tcpClientListener);}Overridepublic void onClick(View view) {if (view.getId() R.id.connect_button) {if (client_edit.getText().toString().trim().length() 0) {Toast.makeText(getActivity(), 请输入服务端IP, Toast.LENGTH_SHORT).show();} else {if (!client_connect) {client_connect true;tcpClientRunnable.setIp(client_edit.getText().toString().trim());MyUtils.ExecuteRunnable(tcpClientRunnable);client_edit.setText(MyUtils.getLocalIp());client_edit.setEnabled(false);connect_button.setText(断开);} else {client_connect false;tcpClientRunnable.close();client_edit.setText(client_edit.getText().toString().trim());client_edit.setEnabled(true);connect_button.setText(连接);}}}}Overridepublic void onDestroy() {super.onDestroy();tcpClientRunnable.close();}TcpClientRunnable.ClientListener tcpClientListener new TcpClientRunnable.ClientListener() {Overridepublic void onClientConnect() {Log.i(TAG,TCP连接成功跳转DisplayActivity);Intent intent new Intent(getActivity(), DisplayActivity.class);startActivity(intent);}Overridepublic void onClientClose() {ToastUtils.showShort(TCP连接断开);}Overridepublic void onClientReceiveBitmap(Bitmap bitmap, int width, int height) {MyUtils.setBitmap(bitmap, width, height);}}; } 至此通过Socket实现的手机局域网投屏软件完成。