1. 程式人生 > >基於netty框架實現的TCP服務端程式

基於netty框架實現的TCP服務端程式

工程目錄結構


程式碼:NioServer main類



import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;


import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
/** 
 * Netty 服務端程式碼 
 *  
 */  
public class NioServer {  
  
/**
* 日誌物件
*/
//protected static Logger logger = LoggerFactory.getLogger(NioServer.class);
private static int port = 9999;
    public static void main(String args[])  {  
   
        // Server服務啟動器  
        ServerBootstrap bootstrap = new ServerBootstrap();  
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
        bootstrap.group(bossGroup, workerGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel  ch) throws Exception {
//可以在socket接上來的時候新增很多指定義邏輯
ch.pipeline().addLast("encode",new StringEncoder());      
ch.pipeline().addLast("decode",new StringDecoder());  
ch.pipeline().addLast("ping", new IdleStateHandler(25, 15, 10,TimeUnit.SECONDS));
ch.pipeline().addLast(new  NioServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
        // Bind and start to accept incoming connections. 
        ChannelFuture future = bootstrap.bind(port).sync();
//        logger.info("server started ,listen {}" ,port);
        System.out.println("開始監聽 "+ port);
        //啟動一個執行緒 來給客戶端發訊息
        //new Thread(new ServerTask()).run();
           // Wait until the server socket is closed.
           // In this example, this does not happen, but you can do that to gracefully
           // shut down your server. 呼叫實現優雅關機
           future.channel().closeFuture().sync();
    } catch (InterruptedException e) {
e.printStackTrace();
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
    }
    }  
}  
class ServerTask implements Runnable{
/**
* 日誌物件
*/
//protected Logger logger = LoggerFactory.getLogger(ServerTask.class);
public void run() {
Channel channel = null;
Map.Entry<String, Channel>  entry = null;
while (true) {
Iterator<Entry<String, Channel>> it = GatewayService.map.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
channel = entry.getValue();
if (channel.isActive() && channel.isWritable()) {
entry.getValue().writeAndFlush(new Date() + "我是測試的伺服器端向客戶端發資料");
} else {
channel.close();
it.remove();
System.out.println("通道不能連線uid:{ },伺服器關閉和刪除它 "+ entry.getKey());
//logger.info("channel cannot connect uid : {}, server close and remove it" ,entry.getKey());
}
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


}

 //GatewayService.java

import io.netty.channel.Channel;


import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class GatewayService {
/**
* 日誌物件
*/
//protected static Logger logger = LoggerFactory.getLogger(GatewayService.class);
/**
* 存放客戶端連線
*/
public static Map<String,Channel> map = new ConcurrentHashMap<String, Channel>();
/**
* 新增一個客戶端連線
* @param uid
* @param socketChannel
*/
public static void add(String uid,Channel channel){
if (map.containsKey(uid)) {
Channel temp =map.get(uid);
if (!(temp.isActive() && temp.isWritable())){
map.remove(uid);
map.put(uid, channel);
}
} else {
map.put(uid, channel);
}
  System.out.println("新增一個客戶端uid : " +uid + "當前客戶端數量  :"+getClientSize());
 
}
/**
* 移除一個客戶端連線
* @param uid
*/
public static void remove(String uid){
Channel channel = map.remove(uid);
channel.close();
 
 System.out.println("刪除一個客戶端uid : " +uid + "  當前客戶端數量  :"+ getClientSize());
}
/**
* 當前客戶端數量
* @return
*/
public static int getClientSize(){
return map.size();
}
}

NioServerHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;


/**
 * 實際的業務處理類
 * 
 * @liuguodong
 *
 */
public class NioServerHandler extends SimpleChannelInboundHandler<String> {


/**
* 日誌物件
*/
//protected Logger logger = LoggerFactory.getLogger(NioServerHandler.class);


@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {


super.channelRegistered(ctx);


System.out.println("--------服務註冊 通道 -------");
}


@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg)
throws Exception {

System.out.println("server--->收到客戶端發的訊息:" + msg);
ctx.writeAndFlush("Received your message !\n"+msg+'\n');
System.out.println("server--->服務端返回的資訊:" + msg+" # ");
GatewayService.add("11", ctx.channel());
}


@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//  ctx.writeAndFlush("Received your message !\n");
//  ctx.writeAndFlush("你好 !\n");
super.channelActive(ctx);



 System.out.println("--------通道啟用-------");
}


/**
* 響應netty 心跳  這個可以給客戶端傳送一些特定包 來標識
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
super.userEventTriggered(ctx, evt);
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent) evt;
//多少秒沒有讀
if (e.state() == IdleState.READER_IDLE) {


//System.out.println("讀超時.....");
} else if (e.state() == IdleState.WRITER_IDLE) {//多少秒沒有寫
//ctx.close();

//System.out.println("寫超時.....");
}else if (e.state() == IdleState.ALL_IDLE) { //總時間
          
//                System.out.println("總超時.....");
                //ctx.close();
                //可以發包了, 然後發出去後  客戶單迴應一個 這時就不會進入read了 來判斷心跳
            }
}
}


@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
try {
super.exceptionCaught(ctx, cause);
} catch (Exception e) {
  System.out.println("服務異常 ....關閉連線");
 
ctx.close();
}
}


}

原始碼地址:http://download.csdn.net/download/liu3364575/9966543

相關推薦

基於netty框架實現TCP服務程式

工程目錄結構 程式碼:NioServer main類 import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.Channel

Java通過 Socket 實現 TCP服務(一個實例)

trac write 建立 回復 狀態 else 應用程序 字符 system 1 Java Socket簡介   所謂socket 通常也稱作”套接字“,用於描述IP地址和端口,是一個通信鏈的句柄。應用程序通常通過”套接字”向網絡發出請求或者應答網絡請求。Socket和S

Python socket模塊實現TCP服務客戶

python socket Python socket模塊實現TCP服務端客戶端 寫了詳細的註釋,如果有哪一行不明白,可留言哦。 服務端腳本 # _*_ coding: utf-8 _*_ __author__ = ‘xiaoke‘ __date__ = ‘2018/6/13 14:39‘ # 這個

基於netty實現rpc框架-spring boot服務

demo地址 https://gitee.com/syher/grave-netty   RPC介紹 首先了解一下RPC:遠端過程呼叫。簡單點說就是本地應用可以呼叫遠端伺服器的介面。那麼通過什麼方式呼叫遠端介面呢?說白了RPC只是一種概念。他的呼叫可以基於HTTP實現,也可以基於TCP/IP實現。甚

基於select非阻塞模型的服務程式示例(Winsock2實現

/* 總結: ①無論阻塞還是非阻塞,select都不會立即返回,select就是用於非阻塞模型中的。 ②將SOCKET置於非阻塞模式下時,處理連線或處理收發資料的Socket API都會立即返回。 ③select會監視fd_set中的所有套接字,一旦有套接字發生IO事件(包括客戶端的連

go語言實現 tcp客戶/服務

tcpl sem close byte cpc cep 實現 lee n) / server.go /package main import ("bufio""fmt""net""time")

Qt:Qt實現Winsock網路程式設計—TCP服務和客戶通訊(多執行緒)

Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊(多執行緒) 前言 感覺Winsock網路程式設計的api其實和Linux下網路程式設計的api非常像,其實和其他程式語言的網路程式設計都差不太多。博主用Qt實現的,當然不想用黑視窗唄,有介面可以看到,由於GUI程式設計

nettytcp服務

jar包下載,http://pan.baidu.com/s/1hr2VBzY import org.apache.log4j.Logger; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel

Pomelo(一):網易開源基於 Node.js 的遊戲服務框架

  Pomelo 是基於 Node.js 的高效能、分散式遊戲伺服器框架。它包括基礎的開發框架和相關的擴充套件元件(庫和工具包),可以幫助你省去遊戲開發枯燥中的重複勞動和底層邏輯的開發。Pomelo 不但適用於遊戲伺服器開發, 也可用於開發高實時 Web 應用,它的分散式架構可以使 Pomelo 比普通

php編寫TCP服務和客戶程式

1、修改php.ini,開啟extension=php_sockets.dll 2、服務端程式SocketServer.php <?php //確保在連線客戶端時不會超時 set_time_limit(0); //設定IP和埠號 $address =

Netty編寫第一個服務與客戶應用程式

服務端        所有的 Netty 伺服器都需要以下兩部分        至少有一個 ChannelHandler:該遵紀安實現了伺服器對客戶端接受的資料的處理邏輯,即業務邏輯        引導(ServerBootStrap):這是配置伺服器的啟動程式碼。它必須繫結

C++封裝的基於WinSock2的TCP服務、客戶

  無聊研究Winsock套接字程式設計,用原生的C語言介面寫出來的程式碼看著難受,於是自己簡單用C++封裝一下,把思路過程理清,方便自己後續翻看和新手學習。   只寫好了TCP通訊服務端,有空把客戶端流程也封裝一下。   先上主函式: // main.cpp : 異想家s

python web自制框架之-完整服務實現

今天我們做下服務端的完整實現,把路由與模型分開來。首先是run函式,實現接收請求與返回客戶端資料1.def run(host='', port=3000): """ 啟動伺服器 """ # 初始化 socket 套路 log(

Go實戰--實現一個簡單的tcp服務和客戶(The way to go)

生命不止,繼續 go go go !!! 之前介紹了go為我們提供的net/http包,很方便的建立一些api。 今天就來點實戰,寫一個簡單的tcp的服務端、客戶端程式。 按照國際慣例,還是先介紹一點點基礎知識。 * net.Listen* Liste

Redis 服務程式實現原理

上篇我們簡單介紹了 redis 客戶端的一些基本概念,包括其 client 資料結構中對應的相關欄位的含義,本篇我們結合這些,來分析分析 redis 服務端程式是如何執行的。一條命令請求的完成,客戶端服務端都經歷了什麼?服務端程式中定時函式 serverCron 都有哪些邏輯? ### 一、redis 客戶

部署基於.netcore5.0的ABP框架後臺Api服務,以及使用Nginx部署Vue+Element前端應用

前面介紹了很多關於ABP框架的後臺Web API 服務端,以及基於Vue+Element前端應用,本篇針對兩者的聯合部署,以及對部署中遇到的問題進行處理。ABP框架的後端是基於.net core5.0 的Asp.net core 應用,因此和常規的Asp.net core 應用部署一樣;而Vue+Elemen

tcp 服務和客戶程序設計

cti ida ons uint8_t 文件 數據 開頭 ews 信息 一、實驗目的 學習和掌握Linux下的TCP服務器基本原理和基本編程方法,體會TCP與UDP編程的不同,UDP編程:http://blog.csdn.net/yueguanghaidao/articl

編寫一個簡單的TCP服務和客戶

不同的 大連 終端 服務器端 com 讀寫 所有 字數 資料 下面的實驗環境是linux系統。 效果如下: 1.啟動服務端程序,監聽在6666端口上 2.啟動客戶端,與服務端建立TCP連接 3.建立完TCP連接,在客戶端上向服務端發送消息 4.斷開

初識Netty -- 基於Netty的DayTime時間服務

java netty 1. 關於Netty的基本認知:在JDK 1.4推出Java NIO之前,基於Java的所有Socket通信都采用的BIO(同步阻塞式IO),同步阻塞式IO存在巨大的性能和可靠性瓶頸,無法適用於高性能服務器的開發。雖然後來出現了偽異步I/O通信框架,但它僅僅是對之前I/O線程模型

java在線聊天項目0.9版 實現服務接收到的信息返回給每一個客戶窗口中顯示功能之客戶接收

nec 一個 out for tex ava 添加 implement com 客戶端要不斷接收服務端發來的信息 與服務端不斷接收客戶端發來信息相同,使用線程的方法,在線程中循環接收 客戶端修改後代碼如下: package com.swift; import java.