TCP (transmission control protocol) 传输控制协议,是一个面向连接的,可靠的,基于字节流的传输层通信协议,很多应用层协议都建立在tcp之上,程序也可以直接使用tcp运行网络编程
网络通信四层参考模型:
应用层: http等,专门规定某种服务通信步骤,数据具体含义等
传输层:tcp ,udp 负责一段数据(多个数据包)整个传输过程的控制
网际互联层 :ip 负责数据分段打包以及单个数据包如何传输到目标主机
网络接入层: 主机到网际互联层的接口
基于tcp的网络编程
网络编程,主要是指基于tcp的网络通信编程,使用socket类实现,也称为socket编程
socket编程模型中有服务器端和客户端,服务器端使用serversocket创建,一般有固定的ip地址和端口号,方便向外界提供服务,客户端可以有多个,并且使用socket主动连接服务器,连接后,服务器端也创建一个socket对象表示此次连接
服务器端的socket记录了客户端的ip地址和端口号
客户端的socket记录了服务器端的ip地址和端口号
连接的本质就是通过对方的ip地址和端口号找到对方
public class Server1
{
public static void main(String[] args) throws IOException
{
//不明确指定ip地址是因为这段程序运行在哪个机子上,这个机子地址就是他的ip地址
//所以说这个服务器运行的ip地址依赖于他所运行的计算机,所以不需要指定ip地址
ServerSocket server=new ServerSocket(100001);
//当线程执行到这个方法时,这个线程会阻塞,等待,知道客户端发来这个请求
Socket socket=server.accept();
//由于服务器端是可以接收多个客户端请求,一般要开启新的线程,这里我们就暂时省略,直接用输入输出流进行数据交换
//输入流,可以从客户端读取数据
InputStream inputStream=socket.getInputStream();
//输出流,可以向客户端发送数据
OutputStream outputStream=socket.getOutputStream();
//拿到输入输出流之后,我们就可以进行数据交换
//向客户端发送数据,协议等东西内部已经封装,我们只需要知道调用这个方法就行
outputStream.write("hello".getBytes());
//关闭资源
socket.close();
}
}
public class Client1
{
public static void main(String[] args) throws UnknownHostException, IOException
{
//客户端使用socket来创建,指定IP地址和端口号
Socket socket=new Socket("localhost", 100001);
//输入流,从服务器端读取数据
InputStream inputStream=socket.getInputStream();
//输出流,向服务器端输出数据
OutputStream outputStream=socket.getOutputStream();
byte[] buff=new byte[1024];
int len=inputStream.read(buff);
//读取缓存区的字节,一定要用参数指定读取多少长度(因为缓存区要读满,不加参数,他会把这个缓存年数据读完)
System.out.println(new String(buff,0,len));
socket.close();
}
}
客户端与服务端相互通信的例子
public class Server2
{
public static void main(String[] args)
{
ServerSocket server;
Socket socket;
try
{
server=new ServerSocket(10003);
socket = server.accept();
mythread myThread=new mythread(socket);
myThread.start();
} catch (IOException e1)
{
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
class mythread extends Thread{
Socket socket;
public mythread(Socket socket){
this.socket=socket;
}
@Override
public void run()
{
try
{
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line=null;
while((line=bufferedReader.readLine())!=null){
if("over".equalsIgnoreCase(line)){
break;
}
char[] ch=line.toCharArray();
//反转字符串
for(int i=0;i<ch.length/2;i++){
char ch1;
ch1=ch[i];
ch[i]=ch[ch.length-1-i];
ch[ch.length-1-i]=ch1;
}
bufferedWriter.write(ch);
bufferedWriter.newLine();
bufferedWriter.flush();
}
} catch (IOException e)
{
e.printStackTrace();
} finally{
try
{
socket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public class Client2
{
public static void main(String[] args)
{
Socket socket=null;
String line=null;
Scanner scanner=null;
try
{
socket=new Socket("localhost", 10003);
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
scanner=new Scanner(System.in);
while((line=scanner.nextLine())!=null){
bufferedWriter.write(line);
bufferedWriter.newLine();
bufferedWriter.flush();
//从服务器端接收
line=bufferedReader.readLine();
if(line!=null){
System.out.println(new String(line));
}
else{
break;
}
}
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally{
try
{
socket.close();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
bufferedInputStream 和bufferedReader的区别在于一个是针对字符流的,一个是针对字节流的,bufferedInputStream 在实现自身read方法中提供缓存,是一次取1024或者更多字节然后在慢慢读,一个个的返回,它并没有实现读一行的方法。
bufferedReader在实现时通过提供一个readLine方法,使用数组或者stringBuilder存储一行数据,并一次性返回
inputStreamReader 将字节流转换为字符流,是字节流通向字符流的桥梁,默认编码gbk,可以更改编码