TCP编程
Java中的TCP
java对TCP协议进行了封装,客户端和服务端都使用Socket代表两个的通信端口,不过客户端使用的是Socket类,服务端使用的是ServerSocket.
客户端代码示例
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端套接字数据,参数是目的服务器的IP地址和端口
Socket socket = new Socket("127.0.0.1",8080);
//根据套接字创建套接字输出流
OutputStream os = socket.getOutputStream();
String str="今天天气好";
//输出流写入
os.write(str.getBytes());
socket.close();
}
}
服务端代码示例
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建一个服务器接收套接字对象,参数应该是服务器上的端口
ServerSocket ss = new ServerSocket(8080);
//监听客户端发送的套接字对象
Socket socket = ss.accept();
//根据套接字获取字节输入流
InputStream is = socket.getInputStream();
//操作套接字输入流
byte[] bytes = new byte[1024];
int len;
while ((len= is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//先开后关
is.close();
ss.close();
}
}
必须先开启服务端,再开启客户端
多发多收
DataInputStream 和 DataOutputStream 是数据字节流,分别继承了FilterInputStream和FilterOutputStream,爷爷类是InputStream和OutputStream
作用
用来封装和装饰其他字节流
客户端代码示例
public class ClientDemo {
public static void main(String[] args) {
//JDK7的新特性,try-with-resources
//格式: try(启用的资源) {} catch(e) {}
//作用,自动为启用的资源关流,凡是实现了Closeable接口的,都需要关流
try (Socket socket = new Socket("localhost",8080);){
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
while (true){
String next = sc.next();
dos.writeUTF(next);
dos.flush();
if (next.equals("886")){
System.out.println("客户端停止");
break;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
服务端代码示例
public class ServerDemo {
public static void main(String[] args) {
try (ServerSocket ss = new ServerSocket(8080);
Socket accept = ss.accept();
) {
InputStream is = accept.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true) {
try {
//报EOFException异常意味着,流已经读到末尾了
String s = dis.readUTF();
System.out.println(s);
} catch (EOFException e) {
//getRemoteSocketAddress() 获取客户端IP地址
System.out.println(accept.getRemoteSocketAddress() + "下机了");
break;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
自由发送
以上代码有个缺点,next()和readUTF()方法都会造成阻塞,这会导致信息以固定的模式发送:客户端发送--->服务端接收--->服务端发送--->客户端接收,因此应该设置两个线程,让两端发送时互不干涉。
客户端代码示例
public class ClientDemo {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8080)
) {
//封装套接字输入流,用于接收数据
DataInputStream dis = new DataInputStream(socket.getInputStream());
//封装套接字输出流,用于发送数据
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
//创建键盘输入流
Scanner sc = new Scanner(System.in);
System.out.println("开始聊天");
//获取对方的IP地址,先获取原始格式,再强转成InetSocketAddress
InetSocketAddress rsa = (InetSocketAddress) socket.getRemoteSocketAddress();
String server = rsa.getHostString();
//创建一个线程用来服务端发送数据,客户端接收数据,避免readUTF() 造成的阻塞问题
new Thread() {
@Override
public void run() {
//接送数据
try {
while (true) {
String rMsg = dis.readUTF();
System.out.println("我是服务端" + server + ":" + rMsg);
}
} catch (IOException e) {
System.out.println("客服已下线,请为客服打分吧");
}
}
}.start();
while (true) {
String s = sc.nextLine();
//发送数据
dos.writeUTF(s);
dos.flush();
//当客户端输入886,终止循环
if (s.equals("886")) {
System.out.println("我是客户端,我下机了");
break;
} else {
System.out.println("我是客户端:" + s);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端代码示例
public class ServerDemo {
public static void main(String[] args) {
try (
//创建服务器套接字对象ServerSocket,并监听指定端口
ServerSocket ss = new ServerSocket(8080);
//监听客户端,并获取客户端套接字对象
Socket accept = ss.accept();
) {
//读取并接收数据
//获取套接字输入流,接收数据
DataInputStream dis = new DataInputStream(accept.getInputStream());
//获取套接字输出流,发送数据
DataOutputStream dos = new DataOutputStream(accept.getOutputStream());
//获取对方的IP
InetSocketAddress rsa = (InetSocketAddress) accept.getRemoteSocketAddress();
String client = rsa.getHostString();
Scanner sc = new Scanner(System.in);
//创建另一个线程用来客户发送数据,服务端接收数据,避免readUTF() 造成的阻塞问题
new Thread(() -> {
try {
//循环接收数据
while (true) {
String s = dis.readUTF();
System.out.println("我是客户端" + client + ":" + s);
}
} catch (IOException e) {
System.out.println("用户已下线");
;
}
}).start();
//循环发送
while (true) {
try {
//发送数据
String s1 = sc.next();
dos.writeUTF(s1);
System.out.println("我是服务端:" + s1);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
标签:String,编程,System,TCP,println,new,out,客户端
From: https://www.cnblogs.com/qifenku/p/17295149.html