我正在开发一个需要用户之间进行实时交互的项目。我希望有一个HTML5 Web客户端(足够简单)和一个本地客户端(最好是Java),它们都可以连接到服务器。我做了一些研究,但没有找到关于本地客户端是否可以在没有浏览器的情况下连接到服务器的确定答案。
问题:有没有办法在没有浏览的情况下从本地Java客户端连接到websocket服务器?我已经看到其他语言中的一些浏览器包装器可能使这成为可能。如果没有,我愿意接受建议。
感谢。
答案 0 :(得分:8)
您当然可以在浏览器沙箱之外使用Java中桌面应用程序的WebSockets。这背后的想法是您可以创建创建TCP连接的胖客户端,因此他们当然应该能够在这些TCP连接之上创建WebSocket连接。
这样做的最新和最好的API之一是由Kaazing编写的,它认为WebSocket就像一个套接字,可以使用简单的“ws://”URI创建。
详细讨论了API on the Kaazing Gateway 5.0 Java WebSocket Documentation site。您可以从Kaazing here
下载普通网关创建一个websocket:
import com.kaazing.net.ws.WebSocket;
import com.kaazing.net.ws.WebSocketFactory;
wsFactory = WebSocketFactory.createWebSocketFactory();
ws = wsFactory.createWebSocket(URI.create("ws://example.com:8001/path"));
ws.connect(); // This will block or throw an exception if failed.
要发送消息,请添加WebSocketMessageWriter对象:
WebSocketMessageWriter writer = ws.getMessageWriter();
String text = "Hello WebSocket!";
writer.writeText(text); // Send text message
要接收或使用消息,请添加WebSocket和WebSocketMessageReader对象:
wsFactory = WebSocketFactory.createWebSocketFactory();
ws = wsFactory.createWebSocket(URI.create("ws://example.com:8001/path"));
ws.connect(); // This will block or throw an exception if failed.
WebSocketMessageReader reader = ws.getMessageReader();
WebSocketMessageType type = null; // Block till a message arrives
// Loop till the connection goes away
while ((type = reader.next()) != WebSocketMessageType.EOS) {
switch (type) { // Handle both text and binary messages
case TEXT:
CharSequence text = reader.getText();
log("RECEIVED TEXT MESSAGE: " + text.toString());
break;
case BINARY:
ByteBuffer buffer = reader.getBinary();
log("RECEIVED BINARY MESSAGE: " + getHexDump(buffer));
break;
}
}
(完全披露:我曾在Kaazing Corporation担任服务器工程师。)
答案 1 :(得分:6)
您也可以考虑使用JSR 356 - Java API for WebSocket。它是Java EE 7的一部分,但客户端可以从普通的Java SE运行而不会出现任何问题。现在有多种可用的实现,后面的所有实现都可以使用:
程序化API:
final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
Session session = webSocketContainer.connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig config) {
// session.addMessageHandler( ... );
}
}, URI.create("ws://some.uri"));
带注释的API:
public static void main(String[] args) throws IOException, DeploymentException {
final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
webSocketContainer.connectToServer(MyEndpoint.class, URI.create("ws://some.uri"));
}
@ClientEndpoint
public static class MyEndpoint {
// text
@OnMessage
void onMessage(Session session, String message) {
// ...
}
// binary
@OnMessage
void onMessage(Session session, ByteBuffer message) {
// ...
}
// @OnClose, @OnOpen, @OnError
}
请参阅链接页面了解更多详情(完整规格)。
这里有各种实现,基本上每个Java容器都有一个。我正在开发Glassfish / WebLogic实现及其名为Tyrus,请随意尝试(我们提供易于使用的所有功能,请参阅http://search.maven.org/...)。
答案 2 :(得分:3)
Vert.x有一个java websocket客户端:
VertxFactory.newVertx()
.createHttpClient()
.setHost("localhost")
.setPort(8080)
.connectWebsocket("/ws", new Handler<WebSocket>() {
@Override
public void handle(final WebSocket webSocket) {
// Listen
webSocket.dataHandler(new Handler<Buffer>() {
@Override
public void handle(Buffer buff) {
log.info("Received {}", buff.toString());
}
});
// Publish
webSocket.writeTextFrame("Heya");
}
});
答案 3 :(得分:1)
Netty
是这项任务的不错选择,它是一个高性能的网络应用程序框架,它优雅地支持SSL,这里是来自netty github的netty websocket client example:
public final class WebSocketClient {
static final String URL = System.getProperty("url", "ws://127.0.0.1:8080/websocket");
public static void main(String[] args) throws Exception {
URI uri = new URI(URL);
String scheme = uri.getScheme() == null? "ws" : uri.getScheme();
final String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
final int port;
if (uri.getPort() == -1) {
if ("ws".equalsIgnoreCase(scheme)) {
port = 80;
} else if ("wss".equalsIgnoreCase(scheme)) {
port = 443;
} else {
port = -1;
}
} else {
port = uri.getPort();
}
if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
System.err.println("Only WS(S) is supported.");
return;
}
final boolean ssl = "wss".equalsIgnoreCase(scheme);
final SslContext sslCtx;
if (ssl) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
// If you change it to V00, ping is not supported and remember to change
// HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
final WebSocketClientHandler handler =
new WebSocketClientHandler(
WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders()));
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), host, port));
}
p.addLast(
new HttpClientCodec(),
new HttpObjectAggregator(8192),
WebSocketClientCompressionHandler.INSTANCE,
handler);
}
});
Channel ch = b.connect(uri.getHost(), port).sync().channel();
handler.handshakeFuture().sync();
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = console.readLine();
if (msg == null) {
break;
} else if ("bye".equals(msg.toLowerCase())) {
ch.writeAndFlush(new CloseWebSocketFrame());
ch.closeFuture().sync();
break;
} else if ("ping".equals(msg.toLowerCase())) {
WebSocketFrame frame = new PingWebSocketFrame(Unpooled.wrappedBuffer(new byte[] { 8, 1, 8, 1 }));
ch.writeAndFlush(frame);
} else {
WebSocketFrame frame = new TextWebSocketFrame(msg);
ch.writeAndFlush(frame);
}
}
} finally {
group.shutdownGracefully();
}
}
}
public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
private final WebSocketClientHandshaker handshaker;
private ChannelPromise handshakeFuture;
public WebSocketClientHandler(WebSocketClientHandshaker handshaker) {
this.handshaker = handshaker;
}
public ChannelFuture handshakeFuture() {
return handshakeFuture;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
handshakeFuture = ctx.newPromise();
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
handshaker.handshake(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("WebSocket Client disconnected!");
}
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
System.out.println("WebSocket Client connected!");
handshakeFuture.setSuccess();
return;
}
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new IllegalStateException(
"Unexpected FullHttpResponse (getStatus=" + response.status() +
", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
}
WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof TextWebSocketFrame) {
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
System.out.println("WebSocket Client received message: " + textFrame.text());
} else if (frame instanceof PongWebSocketFrame) {
System.out.println("WebSocket Client received pong");
} else if (frame instanceof CloseWebSocketFrame) {
System.out.println("WebSocket Client received closing");
ch.close();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
}
ctx.close();
}
}