网络编程2
一、什么是TCP,它的优缺点是什么?
TCP--传输控制协议[有连接的协议]
优点:保证数据安全可靠
缺点:消耗大,效率低
二、建立基于TCP的网络通讯程序需要使用的类和常用方法?
基于TCP的网络通讯程序是区分客户端和服务器端
创建客户端程序
1.java.net Class Socket 创建基于TCP的通讯程序的客户端对象的java类
通过这个类创建的对象就表示一个客户端
2.构造方法
Socket(InetAddress address, int port) |
创建流套接字并将其连接到指定IP地址的指定端口号。 |
Socket(String host, int port) |
创建流套接字并将其连接到指定主机上的指定端口号。 |
3.常用实例方法
OutputStream |
getOutputStream() 返回此套接字的输出流。 |
|
InputStream |
getInputStream() 返回此套接字的输入流。 |
|
void |
close() 关闭此套接字。 |
创建服务器端程序
1.java.net Class ServerSocket 创建基于TCP的通讯程序的服务器端对象的java类
通过这个类创建的对象就表示一个服务器端
2.构造方法
ServerSocket(int port) |
创建绑定到指定端口的服务器套接字。 |
3.实例方法
Socket |
accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】 |
|
void |
close() 关闭此套接字。 |
例如:
完成客户端向服务器送数据,服务器接收到客户端发送来的数据。
客户端向服务器送数据
package com.wangxing.test1;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 基于TCP的客户端【发送数据】
*
* @author 14336
*
*/
public class TestClient1 {
public static void main(String[] args) throws Exception {
//定义服务器端的ip
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port(接口)
int serverport=3000;//(0~1024被系统使用)
//创建客户端对象
Socket client=new Socket(serverIP,serverport);//客户端链接哪个服务器。
//定义Scanner对象获取控制台输入的信息
Scanner input=new Scanner(System.in);
System.out.println("请输入要发送的数据:");
String info=input.nextLine();
//得到输出流
OutputStream outputStream=client.getOutputStream();
//写出数据
outputStream.write(info.getBytes());
//关闭流
outputStream.close();
//关闭客户端Socket
client.close();
}
}
服务器接收到客户端发送来的数据
package com.wangxing.test1;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP的服务器【接受数据】
* @author 14336
*
*/
public class TestServer {
public static void main(String[] args) throws Exception {
//指定服务器开启的端口
int serverport=3000;
//创建服务器对象
ServerSocket serverSocket=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接。。。");
//等待客户端连接
//在客户端没有进行连接之前此方法一直阻塞
//serverSocket.accept();此方法是ServerSocket中的方法返回值是Socket类型
Socket client1=serverSocket.accept();
//通过连接进来的客户端对象得到输入流,以接收客户端发送来的数据
InputStream inputStream=client1.getInputStream();
//创建保存发送来数据用的字节数组
byte[] b=new byte[1024];
//读取客户端发送来的数据保存到数组b中
int len=inputStream.read(b);
//将保存在字节数组中的数据转换成String
String msg=new String(b);
System.out.println("接受的数据是:"+msg);
//关闭流
inputStream.close();
//关闭Socket
client1.close();
//关闭服务器
serverSocket.close();
}
}
例如2:
完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
客户端持续向服务器送数据
package com.wangxing.test2;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 基于TCP的客户端【持续发送数据】
* @author 14336
*
*/
public class TestClient2 {
public static void main(String[] args) throws Exception {
//服务器IP
InetAddress serverIP=InetAddress.getLocalHost();
//服务器端口
int serverport=3000;
//客户对象
Socket client=new Socket(serverIP,serverport);
//Scanner
Scanner input=new Scanner(System.in);
//控制循环的变量
boolean flag=true;
//得到输出流
OutputStream outputStream=client.getOutputStream();
//控制持续发送
while(flag){
System.out.println("请输入需要发送的数据:");
String info=input.nextLine();
//写出数据
outputStream.write(info.getBytes());
//根据输入的数据判断是否关闭客户端
if (info.equals("886")) {
flag=false;
}
}
//关闭流
outputStream.close();
//关闭Socket
client.close();
}
}
服务器持续接收到客户端发送来的数据
package com.wangxing.test2;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP的服务器【接受数据】
* @author 14336
*
*/
public class TestServer2 {
public static void main(String[] args) throws Exception {
//指定服务器开启端口
int serverport=3000;
//创建服务器对象
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接:");
//等待客户端连接
Socket client1=server1.accept();
//通过连接进入的客户端对象得到输入流,以接收客户端发送来的数据
InputStream inputStream=client1.getInputStream();
//定义持续接受的控制变量
boolean flag=true;
//创建保存发送来的数据用的字节数组
byte data[]=new byte[1024];
while (flag) {
//读取客户端发送来的数据
int len=inputStream.read(data);
//将保存在字节数组中的数据转换成String
//String(data,0,len)注意这一步,读多少转换多少
// String(data)==String(data,0,data.length),
//a a
//abc abc
//d dbc
String msg =new String(data,0,len);
System.out.println("接受到的数据是:"+msg);
if (msg.equals("886")) {
flag=false;
}
}
//关闭流
inputStream.close();
//关闭Socket
client1.close();
//关闭服务器
server1.close();
}
}
例如2:
完成客户端持续向服务器送数据,还能接收服务器返回的信息,服务器持续接收到客户端发送来的数据,还可以向客户端返回信息。
客户端持续向服务器送数据,还能接收服务器返回的信息
package com.wangxing.test3;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 基于TCP的客户端【持续发送数据】
* @author 14336
*
*/
public class TestClient3 {
public static void main(String[] args) throws Exception {
//定义服务器IP
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port
int serverport=3000;
//创建客户端对象
Socket client=new Socket(serverIP, serverport);
//定义Scanner(扫描)对象
Scanner input=new Scanner(System.in);
//定义控制持续发送的变量
boolean flag=true;
//得到输出流
OutputStream outputStream=client.getOutputStream();
//得到输入流
InputStream inputStream=client.getInputStream();
//定义保存读取数据的字节数组
byte data[]=new byte[1024];
//控制持续发送
while(flag){
System.out.println("请输入要发送的数据:");
String info=input.nextLine();
//写出数据
outputStream.write(info.getBytes());
//根据输入的数据判断是否关闭客户端
if (info.equals("886")) {
System.out.println("客户端关闭!");
flag=false;
}else{
//开始接收服务器返回的数据
int len=inputStream.read(data);
//将读取到的数据保存在字节数组中
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接受来自服务器的数据是:"+msg);
}
}
//最后用哪个,就先关谁
//关闭流
inputStream.close();
outputStream.close();
//关闭Socket
client.close();
}
}
服务器持续接收到客户端发送来的数据,还可以向客户端返回信息
package com.wangxing.test3;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.format.FormatStyle;
/**
* 基于TCP的服务器【接受数据】
* @author 14336
*
*/
public class TestServer3 {
public static void main(String[] args) throws Exception {
//指定服务器开启的端口
int serverport=3000;
//创建服务器对象
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户连接....");
//等待客户连接
Socket client1=server1.accept();
//通过连接进来的客户端对象得到输入流,以接受客户端发来的数据
InputStream inputStream=client1.getInputStream();
//定义持续接受的控制变量
boolean flag=true;
//创建保存发送来的数据用的字节数组
byte[] data=new byte[1024];
//得到输出流
OutputStream outputStream=client1.getOutputStream();
while (flag) {
//读取客户端发送来的数据
int len=inputStream.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接受的数据是:"+msg);
//由接受到的数据控制服务器关闭
if (msg.equals("886")) {
flag=false;
}else {
//开始发送数据
msg="server"+":"+msg;
outputStream.write(msg.getBytes());
}
}
//关闭流
outputStream.close();
inputStream.close();
//关闭Socket
client1.close();
//关闭服务器
server1.close();
}
}
例如:
多客户端,配置一台服务器,独立运行
//客户端
package com.wangxing.test4;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 基于TCP的客户端【持续发送数据】
* @author 14336
*
*/
public class TestClient3 {
public static void main(String[] args) throws Exception {
//定义服务器端的IP
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port端口
int serverport=3000;
//创建客户端对象
Socket client=new Socket(serverIP, serverport);
//定义Scanner
Scanner input=new Scanner(System.in);
//定义控制持续发送的变量
boolean flag=true;
//得到输出流
OutputStream outputStream=client.getOutputStream();
//得到输入流
InputStream inputStream=client.getInputStream();
//定义保存读取数据的字节数组
byte[] data=new byte[1024];
//控制持续发送
//while (!(input.equals("886"))) 中判断条件只能判断一次
while (flag) {
System.out.println("请输入需要发送的数据:");
String info=input.nextLine();
//写出数据
outputStream.write(info.getBytes());
if (info.equals("886")) {
//System.out.println("客户端关闭");
flag=false;
}else{
//开始接收服务器返回的数据
int len=inputStream.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收来自服务器的数据是:"+msg);
}
}
//客户端关闭
System.out.println("客户端关闭!");
//关闭流
outputStream.close();
inputStream.close();
//关闭Socket
client.close();
}
}
//服务器为连接到服务器的每一个客户端构造的线程类
package com.wangxing.test4;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端线程类
* @author 14336
*
*/
public class ClientThread implements Runnable {
private Socket client;
private InputStream in;
private OutputStream out;
private boolean flag=true;
public ClientThread(Socket client) {
this.client=client;
}
public static int CiShu(){
int i=0;
i++;
return i;
}
//完成在服务器中的数据读写操作
@Override
public void run() {
//创建读写数据用户输入输出流对象,就需要客户端对象
try {
in=client.getInputStream();
out=client.getOutputStream();
//定义保存数据的字节数组
byte[] data=new byte[1024];
Thread thread=new Thread();
thread.setName("客户"+CiShu());
while(flag){
//读取数据到字节数组
int len= in.read(data);
//将读取来保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("读取来自"+thread.getName()+"的数据是:"+msg);
//判断退出
if (msg.equals("886")) {
System.out.println("客户端从服务器退出");
//关闭这条线程
flag=false;
}else {
msg="server :"+msg;
out.write(msg.getBytes());
}
}
//关闭流
out.close();
in.close();
//关闭Socket
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//服务器主程序
package com.wangxing.test4;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP的服务器【接收数据】
* @author 14336
*
*/
public class TestServer3 {
public static void main(String[] args) throws Exception {
//指定服务器开启的端口
int serverport=3000;
//创建服务器对象
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接....");
//定义控制接收客户端的变量
boolean flag=true;
while(flag){
//等待客户端连接
Socket client1=server1.accept();
//一旦有客户链接进入服务器成功
//我们就需要为每一个成功进入服务器的客户开启独立的线程
ClientThread ctThread=new ClientThread(client1);
Thread clientThread1=new Thread(ctThread);
//开启线程
clientThread1.start();
}
//关闭服务器
server1.close();
}
}
总结:
客户端程序的开发步骤:
- 创建客户端对象【Socket】,连接服务器
- 通过客户端对象【Socket】的getInputStream() / getOutputStream(),得到输入输出流
- 通过得到的输入输出流对象调用read()/write()方法完成数据收发。
- 关闭输入输出流和客户端对象【Socket】。
服务器端程序的开发步骤:
- 创建服务器端对象【ServerSocket】,开启服务器
- 通过服务器端对象【ServerSocket】的accept()方法,获得连接进入服务器的客户端对象【Socket】
- 连接进入服务器的客户端对象【Socket】的getInputStream() / getOutputStream(),得到输入输出流.
- 通过得到的输入输出流对象调用read()/write()方法完成数据收发。
- 关闭输入输出流和客户端对象【Socket】以及服务器端对象【ServerSocket】。