Introduction to Netty and related basic knowledge
- Netty provides asynchronous event driven network application framework and tools to quickly develop high-performance and reliable network server and client programs.
- Netty provides an easy-to-use API
- Write network communication program based on event driven programming
- Higher throughput
- Low learning difficulty
Introduction and difference of BIO, NIO and AIO
-
Blocking and non blocking
-
Synchronous and asynchronous
-
BIO synchronization blocks IO, and block IO will block threads during IO operation, resulting in low concurrent processing capacity.
-
NIO synchronizes non blocking IO. NIO is an improvement of BIO and is based on Reactor model.
-
AIO(NIO2.0) asynchronous non blocking IO completes the client request processing and notifies the server to start the thread for processing.
Netty Reactor model - single thread model, multi thread model, master-slave multi thread model
-
Single thread model
-
Reactor multithreading model
However, if the concurrency is still large, Reactor still cannot handle a large number of client requests -
Reactor master-slave multithreading model
This thread model is recommended by Netty,
This model is suitable for high concurrency scenarios. A group of thread pools receive requests and a group of thread pools process IO.
Netty - DEMO implementation of simple chat based on web socket
- Import dependency
<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.15.Final</version> </dependency> </dependencies>
- Writing back-end code for Netty Server
public class WebsocketServer { public static void main(String[] args) { //Create two thread pools NioEventLoopGroup mainGroup = new NioEventLoopGroup(); NioEventLoopGroup subGroup = new NioEventLoopGroup(); try { //Create Netty server startup object ServerBootstrap serverBootstrap = new ServerBootstrap(); //Initialize container startup object serverBootstrap //Specify to use the two thread pools created above .group(mainGroup, subGroup) //Specify Netty channel type .channel(NioServerSocketChannel.class) //Specifies that the Channel initializer is used to load when the Channel receives an event //Conduct business processing .childHandler(new WebSocketChanelInitailizer()); //Bind the server port and start the server in a synchronized manner ChannelFuture future = serverBootstrap.bind(9090).sync(); //Wait for the server to shut down future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //Shut down the server mainGroup.shutdownGracefully(); subGroup.shutdownGracefully(); } } }
/** * The channel initializer is used to load the channel handler * * @Author chenppeng * @Date 2021-06-03 10:58 * @Version 1.0 */ @SuppressWarnings("all") public class WebSocketChanelInitailizer extends ChannelInitializer<SocketChannel> { /** * Initialize the channel. This method mainly loads the corresponding ChannelHandler * * @param socketChannel * @throws Exception */ @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //Get the pipeline and load the channelhandlers one by one into the pipeline ChannelPipeline pipeline = socketChannel.pipeline(); //Add an http codec pipeline.addLast(new HttpServerCodec()); //Add a user to support large data flow pipeline.addLast(new ChunkedWriteHandler()); //Add an aggregator, which is mainly used to aggregate HttpMessage into FullHttpRequest/Response pipeline.addLast(new HttpObjectAggregator(1024 * 64)); //You need to specify a route to accept requests //You must use a url ending with the ws suffix to access pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); //Add custom hanlder pipeline.addLast(new ChatHandler()); } }
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { /** * The user saves all client connections */ private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /** * Time format parser */ private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh:MM:ss"); /** * When there is a new event in the Channel, the message will be called automatically * * @param channelHandlerContext * @param textWebSocketFrame * @throws Exception */ @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception { //It will be called automatically after receiving the data //Get the text message sent by the client String text = textWebSocketFrame.text(); System.out.println("The received message data is:" + text); for (Channel client : clients) { //Send messages to all clients client.writeAndFlush(new TextWebSocketFrame(simpleDateFormat.format(new Date()) + ":" + text)); } } /** * This method will be called automatically when a new client li connects to the server * * @param ctx * @throws Exception */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { //Add new channels to clients clients.add(ctx.channel()); } }
- Write front-end code
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Online chat room</title> </head> <body> <label for="message"><input type="text" id="message"></label> <input type="button" value="send message" onclick="SendMessage()"> Received message <p id="server_message" style="background-color: #AAAAAA"></p> <script> let websocket = null; //Judge whether the current browser supports web socket if (window.WebSocket) { //Connect to the server and send a message websocket = new WebSocket("ws://127.0.0.1:9090/ws"); websocket.onopen = function () { console.log("Establish connection"); }; websocket.onclose = function () { console.log("Disconnect") }; websocket.onmessage = function (e) { console.log("Message received from server:" + e.data); document.getElementById("server_message").innerHTML += e.data + "<br>"; } } else { alert("The current browser does not support web socket") } function SendMessage() { let message = document.getElementById("message"); websocket.send(message.value); } </script> </body> </html>
Introduction to MUI, HTML5 +, HBuilder
- MUI official website http://dev.dcloud.net.cn/mui/
- API address: http://dev.dcloud.net.cn/mui/ui/
MUI is a lightweight front-end framework. MUI is based on iOS platform UI and complements some UI controls unique to Android platform. MUI does not rely on any third-party JS library. The compressed JS and CSS files are only 100+K and 60+K. you can customize and download the corresponding modules according to your own needs. And the front end written by MUI can be packaged into APK and IPA installation files and run on the mobile terminal. That is, write a set of code, which can be used in Android
Run under IOS.
- HTML5+ API address http://www.html5plus.org/doc/zh_cn/accelerometer.html#
H5 + provides enhancements to HTML5 and 40WAPI for programmers. Using H5+ API, you can easily develop QR code scanning, camera, map location, message push and other functions
- HBuilder download address http://www.dcloud.io/
User login function
- Background business code
@Override public User login(String username, String password) { if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) { TbUserExample tbUserExample = new TbUserExample(); TbUserExample.Criteria criteria = tbUserExample.createCriteria(); criteria.andUsernameEqualTo(username); List<TbUser> userList = tbUserMapper.selectByExample(tbUserExample); if (userList != null && userList.size() == 1) { String pwd = DigestUtils.md5DigestAsHex(password.getBytes()); if (pwd.equals(userList.get(0).getPassword())) { User user = new User(); BeanUtils.copyProperties(userList.get(0), user); return user; } } } return null; }
Registration function
- Background business code
@Override public void register(TbUser tbUser) { //Judge whether the user exists in the database TbUserExample example = new TbUserExample(); TbUserExample.Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo(tbUser.getUsername()); List<TbUser> userList = tbUserMapper.selectByExample(example); if (userList != null && userList.size() > 0) { throw new RuntimeException("login has failed"); } //Save user information to database tbUser.setId(idWorker.nextId()); tbUser.setPassword(DigestUtils.md5DigestAsHex(tbUser.getPassword().getBytes())); tbUser.setPicSmall(""); tbUser.setPicNormal("l"); tbUser.setNickname(tbUser.getUsername()); tbUser.setCreatetime(new Date()); tbUserMapper.insert(tbUser); }
Introduction and construction of FastDFS file server
FastDFS is an open source distributed file system written in c language. FastDFS is tailor-made for the Internet. It fully considers redundant backup, load balancing, linear capacity expansion and other mechanisms, and pays attention to high availability, high performance and other indicators. It is easy to build a set of high-performance file server cluster using FastDFS to provide file upload, download and other services.
- springboot integrates fastdfs to upload user avatars
- application.properties configuration file
#Consolidate FASTDFS fdfs.soTimeout=1501 fdfs.connectTimeout=601 #Thumbnail generation parameters fdfs.thumbImage.width=150 fdfs.thumbImage.height=150 #TrackerList parameter, supporting multiple fdfs.trackerList[0]=192.168.25.135:22122 #HTTP URL fdfs.httpurl=http://192.168.25.135/
Upload avatar business layer
@Override public User upload(MultipartFile file, String userid) { try { //The url path in the returned fastdfs without http://192.168.1.133/.. String url = fastDFSClient.uploadFile(file); //When fastDFS uploads, it will automatically generate a thumbnail file name_ 150 * 150, suffix String[] fileNameList = url.split("\\."); String fileName = fileNameList[0]; String ext = fileNameList[1]; String picSmallUrl = fileName + "_150x150." + ext; String prefix = environment.getProperty("fdfs.httpurl"); TbUser tbUser = tbUserMapper.selectByPrimaryKey(userid); //Set avatar big picture tbUser.setPicNormal(prefix + url); //Set avatar small picture tbUser.setPicSmall(prefix + picSmallUrl); //Update the new avatar url to the database tbUserMapper.updateByPrimaryKey(tbUser); User user = new User(); BeanUtils.copyProperties(tbUser, user); return user; } catch (IOException e) { e.printStackTrace(); return null; } }