1.什么是TCP协议?
TCP—传输控制协议【有连接的协议】
优点:保证数据安全可靠
缺点:消耗大,效率低
2.TCP协议三次握手
TCP协议在通信的时候,要求通信的双方先建立起连接(面向有连接的协议)。在建立连接的过程中需要经过三次握手才能完成连接的建立。
第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server, Client进入SYN_SENT状态,等待Server确认。【Client给Server发送创建连接的请求】
第二次握手:Server收到数据包后有标志位SYN=1知道Cilent请求建立连接,Server将标志位 SYN和ACK都置为1,ack=J+1,随机传生一个值seq=K,并将该数据包发送给Cilent以确认连接 请求,Server进入SYN_RCVD状态。【Server被Cilent发送响应信息】
第三次握手:Cilent收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志ACK置 为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正 确则连接建立成功,Cilent和Server进入ESTABLISHED状态,完成三次握手,随后Cilent与Server之间可以开始传输数据了。【Client给Server发送确认信息】
3.建立基于TCP的网络通讯程序需要使用的类和常用方法?
上面建立基于TCP的网络通讯程序需要两套程序。
第一套程序,是建立客户端程序
java.net.Socket[套接字] 创建基于TCP的通讯程序的客户端对象的java类
构造方法:
Socket(InetAddress address,int prot)—创建流套接字并将其连接到指定IP地址的指定端口号
Socket(String host,int prot)—创建流套接字并将其连接到指定主机上的指定端口号。
实例方法:
OutputStream getOutputStream()—返回客户端的输出流。【与服务器的输入流连接】
InputStream getInputStream()—返回客户端输入流。【与服务器的输出流连接】
void close()—关闭客户端。
第二套程序,是建立服务器端程序
java.net.ServerSocket 创建基于TCP的通讯程序的服务器端对象的java类
构造方法:
ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
实例方法:
Socket accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
void close() 关闭服务器。
客户端程序的开发步骤:
1.创建客户端对象【Socket】–连接服务器
2.通过客户端对象【Socket】的getInputStream()/getOutputStream()得到输入输出流
3.通过得到的输入输出流对象调用read()/write()方法完成数据收发
4.关闭输入输出流的客户端对象【Socket】
服务器端程序的开发步骤:
1.创建服务器对象【ServerSocket】,开启服务器
2.通过服务器端对象【ServerSocket】的accept()方法,获得连接进入服务器的客户端对象【Socket】
3.连接进入服务器的客户端对象【Socket】的getInputStream()/getOutputStream()得到输入输出流
4.通过得到的输入输出流对调用read()/write()方法完成数据收发
5.关闭输入输出流和客户端对象【Socket】以及服务器端对象【ServerSocket】
例如1:完成客户端向服务器送数据,服务器接收到客户端发送来的数据
package com.wangxing.test1;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端向服务器发送数据
*/
public class CilentClass {
public static void main(String[] args) throws Exception {
//接受控制台数据的输入流
BufferedReader buff=null;
//定义保存服务器地址的对象【String】
InetAddress serverip=null;
//定义连接服务器的端口号
int serverport=3000;
//定义创建客户端对象的Socket
Socket client=null;
//定义发送信息的输出流对象
OutputStream out=null;
//定义保存被发送的数据
String info=null;
//返回包含有本机IP地址的InetAddress对象
serverip=InetAddress.getLocalHost();
//Socket(InetAddress address,int prot)---创建流套接字并将其连接到指定IP地址的指定端口号
client=new Socket(serverip,serverport);
// getOutputStream()---返回客户端的输出流。【与服务器的输入流连接】
out=client.getOutputStream();
System.out.println("请输入发送的数据");
buff=new BufferedReader(new InputStreamReader(System.in));
info=buff.readLine();
out.write(info.getBytes());
out.close();
buff.close();
client.close();
}
}
package com.wangxing.test1;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class ServerClass {
public static void main(String[] args) throws Exception {
//定义连接服务器的端口号
int serverport=3000;
//定义服务器对象
ServerSocket server=null;
//定义保存连接到的服务器的客户端对象
//Socket accept() -侦听要连接到此套接字并接受它。
Socket client=null;
//定义服务器接收客户端信息的输入流对象
InputStream in=null;
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
server=new ServerSocket(serverport);
System.out.println("服务器已经启动,等待客户端连接......");
client=server.accept();
in=client.getInputStream();
int len=in.read(data);
//将读取来保存在字节数组中的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接受的信息是---"+str);
in.close();
client.close();
server.close();
}
}
例如2:完成客户端持续向服务器送数据,服务器持续接收到客户端发送来的数据。
package com.wangxing.test2;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端向服务器发送数据
*/
public class CilentClass {
public static void main(String[] args) throws Exception {
//接受控制台数据的输入流
BufferedReader buff=null;
//定义保存服务器地址的对象【String】
InetAddress serverip=null;
//定义连接服务器的端口号
int serverport=3000;
//定义创建客户端对象的Socket
Socket client=null;
//定义发送信息的输出流对象
OutputStream out=null;
//定义保存被发送的数据
String info=null;
//定义持续输出的变量
boolean flag=true;
//返回包含有本机IP地址的InetAddress对象
serverip=InetAddress.getLocalHost();
//Socket(InetAddress address,int prot)---创建流套接字并将其连接到指定IP地址的指定端口号
client=new Socket(serverip,serverport);
// getOutputStream()---返回客户端的输出流。【与服务器的输入流连接】
out=client.getOutputStream();
buff=new BufferedReader(new InputStreamReader(System.in));
while(flag){
System.out.println("请输入发送的数据");
info=buff.readLine();
out.write(info.getBytes());
if(info.equals("exit")){
flag=false;
}
}
out.close();
buff.close();
client.close();
}
}
package com.wangxing.test2;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class ServerClass {
public static void main(String[] args) throws Exception {
//定义连接服务器的端口号
int serverport=3000;
//定义服务器对象
ServerSocket server=null;
//定义保存连接到的服务器的客户端对象
//Socket accept() -侦听要连接到此套接字并接受它。
Socket client=null;
//定义服务器接收客户端信息的输入流对象
InputStream in=null;
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
//定义控制持续读取数据的变量
boolean flag=true;
server=new ServerSocket(serverport);
System.out.println("服务器已经启动,等待客户端连接......");
//accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
client=server.accept();
in=client.getInputStream();
while(flag){
int len=in.read(data);
//将读取来保存在字节数组中的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接受的信息是---"+str);
if(str.equals("exit")){
flag=false;
}
}
in.close();
client.close();
server.close();
}
}
例如3:完成客户端持续向服务器送数据,还能接收服务器返回的信息,服务器持续接收到客户端发送来的数据,还可以向客户端返回信息。
package com.wangxing.test3;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端向服务器发送数据
*/
public class CilentClass {
public static void main(String[] args) throws Exception {
//接受控制台数据的输入流
BufferedReader buff=null;
//定义保存服务器地址的对象【String】
InetAddress serverip=null;
//定义连接服务器的端口号
int serverport=3000;
//定义创建客户端对象的Socket
Socket client=null;
//定义发送信息的输出流对象
OutputStream sout=null;
//定义接收数据的输入流
InputStream input=null;
//定义保存被发送的数据
String info=null;
//定义持续输出的变量
boolean flag=true;
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
//返回包含有本机IP地址的InetAddress对象
serverip=InetAddress.getLocalHost();
//Socket(InetAddress address,int prot)---创建流套接字并将其连接到指定IP地址的指定端口号
client=new Socket(serverip,serverport);
// getOutputStream()---返回客户端的输出流。【与服务器的输入流连接】
sout=client.getOutputStream();
input=client.getInputStream();
buff=new BufferedReader(new InputStreamReader(System.in));
while(flag){
System.out.println("请输入发送的数据");
info=buff.readLine();
sout.write(info.getBytes());
int len=input.read(data);
//将读取来保存在字节数组中的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接受的信息是---"+str);
if(info.equals("exit")){
flag=false;
}
}
input.close();
sout.close();
buff.close();
client.close();
}
}
package com.wangxing.test3;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class ServerClass {
public static void main(String[] args) throws Exception {
//定义连接服务器的端口号
int serverport=3000;
//定义服务器对象
ServerSocket server=null;
//定义保存连接到的服务器的客户端对象
//Socket accept() -侦听要连接到此套接字并接受它。
Socket client=null;
//定义服务器接收客户端信息的输入流对象
InputStream in=null;
//定义服务器接收客户端信息的输出流对象
OutputStream out=null;
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
//定义控制持续读取数据的变量
boolean flag=true;
server=new ServerSocket(serverport);
System.out.println("服务器已经启动,等待客户端连接......");
//accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
client=server.accept();
in=client.getInputStream();
out=client.getOutputStream();
while(flag){
int len=in.read(data);
//将读取来保存在字节数组中的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接受的信息是---"+str);
if(str.equals("exit")){
flag=false;
}else{
str="server--"+str;
}
out.write(str.getBytes());
}
out.close();
in.close();
client.close();
server.close();
}
}
例如4:多客户端,配置一台服务器,独立运行
package com.wangxing.test4;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端向服务器发送数据
*/
public class CilentClass {
public static void main(String[] args) throws Exception {
//接受控制台数据的输入流
BufferedReader buff=null;
//定义保存服务器地址的对象【String】
InetAddress serverip=null;
//定义连接服务器的端口号
int serverport=3000;
//定义创建客户端对象的Socket
Socket client=null;
//定义发送信息的输出流对象
OutputStream sout=null;
//定义接收数据的输入流
InputStream input=null;
//定义保存被发送的数据
String info=null;
//定义持续输出的变量
boolean flag=true;
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
//返回包含有本机IP地址的InetAddress对象
serverip=InetAddress.getLocalHost();
//Socket(InetAddress address,int prot)---创建流套接字并将其连接到指定IP地址的指定端口号
client=new Socket(serverip,serverport);
// getOutputStream()---返回客户端的输出流。【与服务器的输入流连接】
sout=client.getOutputStream();
input=client.getInputStream();
buff=new BufferedReader(new InputStreamReader(System.in));
while(flag){
System.out.println("请输入发送的数据");
info=buff.readLine();
sout.write(info.getBytes());
int len=input.read(data);
//将读取来保存在字节数组中的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接受的信息是---"+str);
if(info.equals("exit")){
flag=false;
}
}
input.close();
sout.close();
buff.close();
client.close();
}
}
package com.wangxing.test4;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ThreadClass implements Runnable{
//定义创建客户端对象的Socket
private Socket client=null;
//定义服务器接收客户端信息的输入流
private InputStream in=null;
//定义写出数据的输出流对象
private OutputStream out=null;
//定义控制持续读取数据的变量
private boolean flag=true;
public ThreadClass(Socket client){
this.client=client;
}
public void run() {
try {
in=client.getInputStream();
out=client.getOutputStream();
//定义保存客户端发送来的数据的字节数组
byte data[]=new byte[1024];
while(flag){
int len=in.read(data);
//将读取来的数据转换成字符串
String str=new String(data,0,len);
System.out.println("服务器接收的信息是---"+str);
if(str.equals("exit")){
flag=false;
}else {
str="server--"+str;
}
out.write(str.getBytes());
}
out.close();
in.close();
client.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.wangxing.test4;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class ServerClass {
public static void main(String[] args) throws Exception {
//定义连接服务器的端口号
int serverport=3000;
//定义服务器对象
ServerSocket server=null;
//定义保存连接到的服务器的客户端对象
//Socket accept() -侦听要连接到此套接字并接受它。
Socket client=null;
//定义控制持续读取数据的变量
boolean getflag=true;
server=new ServerSocket(serverport);
System.out.println("服务器已经启动,等待客户端连接......");
while(getflag){
//accept() 侦听要连接到此套接字并接受它。 【阻塞主线程运行】
client=server.accept();
//开辟出控制每一个客户端独立读写的线程
ThreadClass thc=new ThreadClass(client);
Thread thread=new Thread(thc);
thread.start();
}
server.close();
}
}