网络编程_2
11.6.什么是TCP,它的优缺点是什么?
TCP–传输控制协议[有连接的协议]
优点:保证数据安全可靠
缺点:消耗大,效率低
11.7.建立基于TCP的网络通讯程序需要使用的类和常用方法?
基于TCP的网络通讯程序是区分客户端和服务器端
创建客户端程序
- java.net Class Socket 创建基于TCP的通讯程序的客户端对象的java类
通过这个类创建的对象就表示一个客户端 - 构造方法:
Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。 - 常用实例方法
类型 | 方法 |
---|---|
OutputStream | getOutputStream() 返回此套接字的输出流。 |
InputStream | getInputStream() 返回此套接字的输入流。 |
void | close() 关闭此套接字。 |
创建服务器端程序
- java.net Class ServerSocket 创建基于TCP的通讯程序的服务器端对象的java类
通过这个类创建的对象就表示一个服务器端 - 构造方法
ServerSocket(int port) 创建绑定到指定端口的服务器套接字。 - 实例方法
Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
void close() 关闭此套接字。
例如:完成客户端向服务器送数据,服务器接收到客户端发送来的数据。
客户端向服务器送数据
package com.wangxing.test1;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient1 {
//客户端
public static void main(String[] args) throws Exception {
//定义保存服务器端ip地址对象
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port
int serverport=3888;
//创建客户端对象
/**
* Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
* Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
*/
Socket cilent=new Socket(serverIP, serverport);
//定义Scanner对象
Scanner input=new Scanner(System.in);
System.out.println("请输入要发送的数据:");
String info=input.next();
//得到输出流
/**
* OutputStream getOutputStream() 返回此套接字的输出流。
* InputStream getInputStream() 返回此套接字的输入流。
* void close() 关闭此套接字。
*/
OutputStream out= cilent.getOutputStream();
//写出数据
//字符串转字节
byte by[]= info.getBytes();
out.write(by);
//关流
out.close();
cilent.close();
}
}
服务器接收到客户端发送来的数据
package com.wangxing.test1;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.CORBA.portable.InputStream;
public class TestServer {
/**
* 服务器
* @param args
*/
public static void main(String[] args)throws Exception {
//指定服务器开启的端口
int serverport=3888;
//创建服务器端对象
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接---");
//客户端连接
/**
* Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
* void close() 关闭此套接字。
*/
Socket client1=server1.accept();
//通过连接进入的客户端对象得到输入流,以接收客户端发送来的数据
java.io.InputStream in=client1.getInputStream();
//创建保存发来的数据用的数组
byte data[]=new byte[1024];
//读取客户端发来的数据
int len=in.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收的数据是:"+msg);
//关流
in.close();
client1.close();
server1.close();
}
}
例如2:完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
客户端持续向服务器送数据
package com.wangxing.test2;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient1 {
//客户端2.0
//完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
//客户端持续向服务器送数据
public static void main(String[] args) throws Exception {
//定义保存服务器端ip地址对象
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port
int serverport=3888;
//创建客户端对象
/**
* Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
* Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
*/
Socket cilent=new Socket(serverIP, serverport);
//定义Scanner对象
Scanner input=new Scanner(System.in);
// System.out.println("请输入要发送的数据:");
// String info=input.next();
//控制持续发送的变量
boolean falg=true;
//得到输出流
/**
* OutputStream getOutputStream() 返回此套接字的输出流。
* InputStream getInputStream() 返回此套接字的输入流。
* void close() 关闭此套接字。
*/
OutputStream out= cilent.getOutputStream();
//写出数据
//字符串转字节
while(falg){
System.out.println("请输入要发送的数据:");
String info=input.next();
byte by[]= info.getBytes();
out.write(by);
if(info.equals("886")){
falg=false;
}
}
//关流
out.close();
cilent.close();
}
}
服务器持续接收到客户端发送来的数据
package com.wangxing.test2;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.CORBA.portable.InputStream;
public class TestServer {
/**
* 服务器
* @param args
*/
public static void main(String[] args)throws Exception {
//指定服务器开启的端口
int serverport=3888;
//创建服务器端对象
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接---");
//客户端连接
/**
* Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
* void close() 关闭此套接字。
*/
Socket client1=server1.accept();
//通过连接进入的客户端对象得到输入流,以接收客户端发送来的数据
java.io.InputStream in=client1.getInputStream();
//创建保存发来的数据用的数组
byte data[]=new byte[1024];
//控制持续接收的变量
boolean falg=true;
//读取客户端发来的数据
while(falg){
int len=in.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收的数据是:"+msg);
if(msg.equals("886")){
falg=false;
}
}
//关流
in.close();
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.util.Scanner;
public class TcpClient1 {
//客户端2.0
//完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
//客户端持续向服务器送数据
public static void main(String[] args) throws Exception {
//定义保存服务器端ip地址对象
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port
int serverport=3888;
//创建客户端对象
/**
* Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
* Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
*/
Socket cilent=new Socket(serverIP, serverport);
//定义Scanner对象
Scanner input=new Scanner(System.in);
// System.out.println("请输入要发送的数据:");
// String info=input.next();
//控制持续发送的变量
boolean falg=true;
//得到输出流
/**
* OutputStream getOutputStream() 返回此套接字的输出流。
* InputStream getInputStream() 返回此套接字的输入流。
* void close() 关闭此套接字。
*/
OutputStream out= cilent.getOutputStream();
//得到输入流
InputStream in=cilent.getInputStream();
//保存读入数据的字节数组
byte data[]=new byte[1024];
//写出数据
//字符串转字节
while(falg){
System.out.println("请输入要发送的数据:");
String info=input.next();
byte by[]= info.getBytes();
out.write(by);
if(info.equals("886")){
falg=false;
}else{
//开始接收服务器返回的数据
int len=in.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收:"+msg);
}
}
//关流
out.close();
in.close();
//关闭socket
cilent.close();
}
}
服务器持续接收到客户端发送来的数据,还可以向客户端返回信息
package com.wangxing.test4;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.CORBA.portable.InputStream;
public class TestServer {
/**
* 服务器
* @param args
*/
public static void main(String[] args)throws Exception {
//指定服务器开启的端口
int serverport=3888;
//创建服务器端对象
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接---");
//客户端连接
/**
* Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
* void close() 关闭此套接字。
*/
Socket client1=server1.accept();
//通过连接进入的客户端对象得到输入流,以接收客户端发送来的数据
java.io.InputStream in=client1.getInputStream();
//通过连接进入的客户端对象得到输出流,以接收客户端发送来的数据
OutputStream out=client1.getOutputStream();
//创建保存发来的数据用的数组
byte data[]=new byte[1024];
//控制持续接收的变量
boolean falg=true;
//读取客户端发来的数据
while(falg){
int len=in.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收的数据是:"+msg);
if(msg.equals("886")){
falg=false;
}else{
//开始发送数据
msg="server-"+msg;
byte by[]=msg.getBytes();
out.write(by);
}
}
//关流
in.close();
out.close();
//关闭socket
client1.close();
//关闭服务器
server1.close();
}
}
例如:多客户端,配置一台服务器,独立运行
多线程:
package com.wangxing.test4;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端线程类
* @author Administrator
*
*/
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;
}
@Override
public void run() {
try {
//创建读写数据用户的输入输出流对象
in=client.getInputStream();
out=client.getOutputStream();
//定义保存数据的数组
byte data[]=new byte[1024];
//持续读写
while(flag){
//将读到的数据保存到数组
int len=in.read(data);
//转String
String msg=new String(data,0,len);
System.out.println("读取的数据是:"+msg);
//判断退出
if(msg.equals("886")){
System.out.println("从客户端退出");
flag=false;
}else{
msg="sever"+msg;
//转byte数组
byte by[]=msg.getBytes();
out.write(by);
}
}
//关流
out.close();
in.close();
//关闭socket
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端:
package com.wangxing.test4;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient1 {
//客户端2.0
//完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
//客户端持续向服务器送数据
public static void main(String[] args) throws Exception {
//定义保存服务器端ip地址对象
InetAddress serverIP=InetAddress.getLocalHost();
//定义服务器端的port
int serverport=3888;
//创建客户端对象
/**
* Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
* Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
*/
Socket cilent=new Socket(serverIP, serverport);
//定义Scanner对象
Scanner input=new Scanner(System.in);
// System.out.println("请输入要发送的数据:");
// String info=input.next();
//控制持续发送的变量
boolean falg=true;
//得到输出流
/**
* OutputStream getOutputStream() 返回此套接字的输出流。
* InputStream getInputStream() 返回此套接字的输入流。
* void close() 关闭此套接字。
*/
OutputStream out= cilent.getOutputStream();
//得到输入流
InputStream in=cilent.getInputStream();
//保存读入数据的字节数组
byte data[]=new byte[1024];
//写出数据
//字符串转字节
while(falg){
System.out.println("请输入要发送的数据:");
String info=input.next();
byte by[]= info.getBytes();
out.write(by);
if(info.equals("886")){
falg=false;
}else{
//开始接收服务器返回的数据
int len=in.read(data);
//将保存在字节数组中的数据转换成String
String msg=new String(data,0,len);
System.out.println("接收:"+msg);
}
}
//关流
out.close();
in.close();
//关闭socket
cilent.close();
}
}
服务器:
package com.wangxing.test4;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.CORBA.portable.InputStream;
public class TestServer {
/**
* 服务器
* @param args
*/
public static void main(String[] args)throws Exception {
//指定服务器开启的端口
int serverport=3888;
//创建服务器端对象
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket server1=new ServerSocket(serverport);
System.out.println("服务器准备完毕,等待客户端连接---");
//定义控制接收客户端的变量
boolean falg=true;
while(falg){
//客户端连接
/**
* Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
* void close() 关闭此套接字。
*/
Socket client1=server1.accept();
//创建目标对象
ClientThread cth=new ClientThread(client1);
Thread clientThread=new Thread(cth);
//启动线程
clientThread.start();
}
//关闭服务器
server1.close();
}
}
总结:
客户端程序的开发步骤:
- 创建客户端对象【Socket】,连接服务器
- 通过客户端对象【Socket】的getInputStream() / getOutputStream(),得到输入输出流
- 通过得到的输入输出流对象调用read()/write()方法完成数据收发。
- 关闭输入输出流和客户端对象【Socket】。
服务器端程序的开发步骤:
- 创建服务器端对象【ServerSocket】,开启服务器
- 通过服务器端对象【ServerSocket】的accept()方法,获得连接进入服务器的客户端对象【Socket】
- 连接进入服务器的客户端对象【Socket】的getInputStream() / getOutputStream(),得到输入输出流.
- 通过得到的输入输出流对象调用read()/write()方法完成数据收发。
- 关闭输入输出流和客户端对象【Socket】以及服务器端对象【ServerSocket】。