使用JDK提供的API进行网络通信,会用到Socket,ServerSocket两个类。写个简单的SERVER和CLIENT之间发消息的小程序,竟然发现了挺多的问题。

这是服务器端代码:

package org.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket; public class ChatServer { public static void main(String[] args) {
ChatServer server = new ChatServer();
server.start();
} public void start() {
while (true) {
ServerSocket s = null;
Socket socket = null;
try {
s = new ServerSocket(10001);
socket = s.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(),true); String content = in.readLine();
System.out.println(content);
content = content + "1";
out.print(content);
out.flush(); // if not flush, client can't receive data in.close();
out.close(); } catch (IOException e) {
e.printStackTrace();
} finally{
try {
s.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

这是客户端代码:

package org.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException; public class Client {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("128.192.184.93", 10001); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.println("hello"); String reply = in.readLine();
System.out.println(reply); in.close();
out.close(); } catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

逻辑很简单:Client会向ChatServer发一个字符串"hello",ChatServer收到后,在这个字符串后面加1,然后发给Client。

这其中遇到了几个问题:

1.PrintWriter构造函数参数autoFlush设置

PrintWriter的构造函数里的第二个参数autoFlush,API文档里解释是:if true, the println,printf, or format methods will flush the output buffer。注意不包括print。

因此,对于ChatServer,32,33行(print),如果不调用flush,Client就收不到数据,尽管在PrintWriter的构造函数里,autoFlush=true;而Client的19行(println),无需调用flush,也能发送数据。

2.Socket的InputStream和OutputStream有关联,如果一个在用,另一个不可关闭

在ChatServer中,如果把35行代码in.close()放到29行之后,30行之前,也就是说,in在读取了数据之后,就关闭掉,造成的后果就是32行代码out.print()失效,这是因为in.close()使socket关闭了,Client只能收到一个null

3.BufferReader的readLine()方法

首先,改方法是阻塞的,如果读不到(即使读到null也算读到),就会阻塞。

该方法会读取一行数据,就是说,读取第一个换行符之前的数据,如果发送的数据中没有换行符,那么,readLine可能会阻塞。

PrintWriter.print()发送的数据中没有换行符,所以多次调用,接受方BufferReader.readLine()读到的数据包括了多次print的数据。

使用jdk的socket通信的更多相关文章

  1. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  2. java Socket通信使用BufferedReader和BufferedWriter的注意事项

    注意事项:readLine()要求有换行标识,write()要输出换行标识,要调用flush()刷新缓冲区. 以下是取自java socket通信中的一小段代码. BufferedReader rea ...

  3. TTMS 一个基于Java Swing的Socket通信的剧院票务管理系统

    TTMS (Theater Ticket Management System) 点我进入github TTMS全称剧院票务管理系统,分为客户端和服务器端.服务器端可以接收客户端连接请求,客户端相当于我 ...

  4. 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?

    这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...

  5. php简单实现socket通信

    socket通信的原理在这里就不说了,它的用途还是比较广泛的,我们可以使用socket来做一个API接口出来,也可以使用socket来实现两个程序之间的通信,我们来研究一下在php里面如何实现sock ...

  6. Socket通信类

    package com.imooc; import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt ...

  7. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  8. socket通信

    socket通信 一:socket基于Tcp连接,数据传输有保证 二:socket连接的建立过程: 1:服务器监听 2:客户端发出请求 3:建立连接 4:通信 三:一个简单的例子:服务器端每隔一段时间 ...

  9. Android之Socket通信、List加载更多、Spinner下拉列表

    Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务 ...

随机推荐

  1. django-crispy-forms入门指南

    django-crispy-forms 是对django form在html页面呈现方式进行管理的一个第三方插件. 配置: 在INSTALLED_APPS中加入'crispy_forms' djang ...

  2. 转:python中函数curry化

    1 柯里化(Currying) 一个函数有多个参数,我们希望能固定其中几个参数的值. from functools import partial def foo(a,b,c): return a+b+ ...

  3. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

      设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...

  4. 基于visual Studio2013解决算法导论之025双向循环链表

     题目 双向循环链表 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <time.h> #in ...

  5. Log4Net五步走

    本文不是教你全面了解log4net,本文只是希望教会你按步就班,照糊芦画瓢般就会用log4net1,引入log4net.dll组件2,建立一个配置文件两种方法,一种是在Web.Config或App.C ...

  6. 12-UIKit(View绘制、绘制曲线、绘制文字、贴图)

    目录: 1. View绘制 2. 绘制曲线 3. 绘制文字 4. 贴图 回到顶部 1. View绘制 1.1 做出自己的视图对象 TRCell : UITableViewCell : UIView U ...

  7. Wince下实现ImageButton

    我们在winform中给按钮设置个背景图片超级简单,是不?可是在wince下面就没那么简单了,下面我来介绍一种方式来实现ImageButton. 实现思路是重新写一个usercontrol就ok.具体 ...

  8. JRE 和 JDK 的区别是什么?

    JRE: Java Runtime Environment JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库.是使用java ...

  9. BZOJ 3173: [Tjoi2013]最长上升子序列( BST + LIS )

    因为是从1~n插入的, 慢插入的对之前的没有影响, 所以我们可以用平衡树维护, 弄出最后的序列然后跑LIS就OK了 O(nlogn) --------------------------------- ...

  10. 前端面试题整理(js)

    1.HTTP协议的状态消息都有哪些? HTTP状态码是什么: Web服务器用来告诉客户端,发生了什么事. 状态码分类: 1**:信息提示.请求收到,继续处理2**:成功.操作成功收到,分析.接受3** ...