Java Socket

一、网络基础

  TCP/IP协议:是以TCP和IP为接触的不同层次上多个协议的集合。

  TCP:传输控制协议  IP:网际协议

  IP地址:为实现网络中不通过计算机之间的通信,每台计算机必须有一个唯一的标识。

  端口:用于区分不同的应用程序,端口号范围为0~65535,其中0~1023位系统所保留。

  IP地址和端口号组成了所谓的Socket,Socket是网络上个运行的程序之间双向通信链路的终结点,是TCP UDP的基础。

二、Java中网络相关API应用

  1)InetAddress

  InetAddress类终于标识网络上的硬件资源,表示IP地址,该类没有构造方法(private),可通过getByAddress(),getByName(),getLocalHost()等静态方法得到InetAddress实例。InetAddress实例可得到当前InetAddress的ip地址 主机名等信息。

public static void main(String[] args) throws UnknownHostException {
//获取本机的InetAddress实例
InetAddress address=InetAddress.getLocalHost();

System.out.println("计算机名:"+address.getHostName());
System.out.println("IP地址:"+address.getHostAddress());

//获取字节数组形式的IP地址
byte[] bytes=address.getAddress();
System.out.println("字节数组形式的IP:"+Arrays.toString(bytes));

//直接输出InetAddress对象
System.out.println(address);

//根据机器名获取InetAddress实例
InetAddress address2=InetAddress.getByName("zhao");
System.out.println(address2);

//根据IP地址获取InetAddress实例
InetAddress address3=InetAddress.getByAddress(bytes);
System.out.println(address3);
}

  2)URL

  URL:统一资源定位符,标识Internet上某一资源的地址,由两部分组成:协议名和资源名称,可以通过String创建URL实例,也可以根据父URL创建子URL实例。

public static void main(String[] args) throws IOException {
//创建一个URL实例
URL imooc=new URL("http://www.imooc.com");
//?后面表示参数 #后面表示锚点
//    URL url=new URL(imooc, "/index.html?username=tom#test");

System.out.println("协议 "+imooc.getProtocol());
System.out.println("主机 "+imooc.getHost());
//如果为指定端口号,则使用默认的端口号,此时getPort方法返回值为-1
System.out.println("端口号 "+imooc.getPort());
//    System.out.println("文件路径 "+url.getPath());
//    System.out.println("文件名 "+url.getFile());
//    System.out.println("相对路径 "+url.getRef());
//    
//通过URL的openStream方法获取URL对象所表示的资源的字节输入流
InputStream inputStream=imooc.openStream();
//将字节输入流转换成字符输入流
InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"utf-8");
//为字符输入流添加缓冲
BufferedReader reader=new BufferedReader(inputStreamReader);
//读取数据
String data=reader.readLine();
while(data!=null){
System.out.println(data);
data=reader.readLine();
}
reader.close();
inputStreamReader.close();
inputStream.close();
}

 

三、Socket

  1)TCP协议是面向连接的,可靠的 有序的 以字节流方式发送数据

  基于TCP协议实现网络通信的类,客户端的Socket类,服务端的Server Socket类

//客户端

package com.zhao.TCPSocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
public static void main(String[] args) throws IOException {
//1:创建客户端Socket,指定服务器地址和端口
InetAddress address=InetAddress.getLocalHost();
try {
Socket socket=new Socket(address,8888);
//2:获取输出流,向服务器端发送登录的信息
OutputStream outputStream=socket.getOutputStream();
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.write("dfasfas");
printWriter.flush();
socket.shutdownOutput(); //关闭输入流

//3:获取输入流,并读取服务器端响应的信息
InputStream inputStream=socket.getInputStream();
InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
String info=null;
while((info=bufferedReader.readLine())!=null)
{
System.out.println("服务器端回复:"+info);
}
//4:关闭资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

 

//服务端

package com.zhao.TCPSocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 基于tcp协议的Socket通信,实现用户登录 服务器端
* 
* @author admin
*
*/
public class Server {
public static void main(String[] args) throws IOException {
// 1:创建一个服务器端Socket,即ServerSocket,绑定指定的端口,并监听此端口
ServerSocket serverSocket = new ServerSocket(8888);

System.out.println("***服务器即将启动,等待客户端的连接***");
//记录客户端的数量
int count=0;

Socket socket=null;
//循环监听,等待客户端的连接
while(true){
// 2:调用accept()方法开始监听,等待客户端的连接

//注:在调用accept()方式时,将进入阻塞状态,等待客户端的请求。当请求到来时,这个Socket实例并没有完成创建,要等到与客户端3次握手完成后,这个Socket才会返回。
socket=serverSocket.accept();
//创建一个新的线程
ServerThread serverThread=new ServerThread(socket);
//启动线程
serverThread.start();

//统计客户端的数量
count++;
System.out.println("客户端的数量: "+count);
}

}
}  

 

 

package com.zhao.TCPSocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
* 服务器线程处理类
* 
* @author admin
*
*/
public class ServerThread extends Thread {
// 和本线程相关的socket
Socket socket = null;

public ServerThread(Socket socket) {
this.socket = socket;
}

// 执行线程的操作,响应客户端的请求
@Override
public void run() {
// 3:获取输入流,读取客户端所发送的信息
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
inputStream = socket.getInputStream();// 字节输入流
inputStreamReader = new InputStreamReader(inputStream);// 将字节流转成字符流
bufferedReader = new BufferedReader(inputStreamReader);// 为字符流添加缓冲
String info = null;
while ((info = bufferedReader.readLine()) != null) {// 循环读取客户端的信息
System.out.println("我是服务器,客户端说 : " + info);
}

socket.shutdownInput();// 关闭输入流

// 4:获取输出流,响应客户端的请求
outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("欢迎您");
printWriter.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 5:关闭资源
try {
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}

}

 

分析:

  对服务器Server:

  1\ 创建一个服务器Socket,即ServerSocket,绑定指定的端口,并监听此端口;

  2\调用accept()方法监听,等待客户端的连接;

  3\获取输入流,读取客户端所发送的信息;

  4\获取输出流,响应客户端请求;

  5\关闭资源。

  在多线程情况下,ServerSocket不关闭,每一个ServerThead类继承Thread类,在run方法中实现上述3 4 5输入流输出流的相关操作以及资源的关闭,在Server中 有while(true)循环监听,等待客户端的连接。

  对客户端Client,和对Server操作大同小异。自定义Socket指定其IP和端口号,在这里用的本机IP,通过InetAddress类获取。

Socket就是IP和端口号,而言指定具体的计算机上具体的线程,网络通信的基础是Socket,服务器监听具体的端口,一旦有客户端访问此端口,服务器也是创建Socket,在服务器 客户机上,两个Socket进行i/o流操作,便完成了网络通信。

  2)UDP以数据报作为数据传输的载体

  进行数据传输时首先要将传输的数据定义成数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口),然后将数据报发送出去。

//客户端

package com.zhao.UDPSocket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Client {
public static void main(String[] args) throws IOException {
/*
* 向服务器端发送数据
*/

//1:定义服务器的地址,端口号和数据
InetAddress address=InetAddress.getLocalHost();
int port=8800;
byte[] bytes="用户名:admin".getBytes();
//2:创建数据报,包含发送的信息
DatagramPacket datagramPacket=new DatagramPacket(bytes, bytes.length, address, port);
//3:创建DatagramSocket对象
DatagramSocket datagramSocket=new DatagramSocket();
//4:向服务器端发送数据报
datagramSocket.send(datagramPacket);

/*
* 接收服务器端响应数据
*/
//1:创建数据报,用于接收服务器端响应的数据
byte[] data=new byte[1024];
DatagramPacket datagramPacket2=new DatagramPacket(data, data.length);
//2:接收服务器端响应的数据
datagramSocket.receive(datagramPacket2);
//3:读物数据
String str=new String(data,0,datagramPacket2.getLength());
System.out.println("我是客户端,服务器说: "+str);
//4:关闭资源
datagramSocket.close();
}
}

 

//服务端

package com.zhao.UDPSocket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/*
* 服务器端,实现基于UDP的用户登录
*/
public class Server {
public static void main(String[] args) throws IOException {
/*
* 接收客户端发送的数据
*/
//1:创建服务器端DatagramSocket,指定端口
DatagramSocket datagramSocket=new DatagramSocket(8800);
//2:穿件数据报,用于接收客户端发送的数据
byte[] bytes=new byte[1024];//创建字节数组,指定接收的数据报的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes, bytes.length);
//3:接收客户端发送的数据
datagramSocket.receive(datagramPacket);//此方法在接收到数据报之前会一直阻塞
//4:读取数据
String info=new String(bytes,0,datagramPacket.getLength());
System.out.println("我是服务器,客户端说 :"+info);

/*
* 向客户端作出响应
*/
//1:定义客户端的地址,端口号和数据
InetAddress address=datagramPacket.getAddress();
int port=datagramPacket.getPort();
byte[] data="欢迎您".getBytes();
//2:创建数据报,
DatagramPacket datagramPacket2=new DatagramPacket(data, data.length, address, port);
//3:响应客户端
datagramSocket.send(datagramPacket2);
//4:关闭资源
datagramSocket.close();

}
}

 

分析:

  1\创建服务器端DatagramSocket,指定监听端口

  2\创建数据报,用于接收客户端发送的数据

  3\接收客户端发送的数据

  4\读取数据

  在客户端,DatagranPacket的创建需要指明服务器地址和端口号。

  对于UDP来说,存信息的是数据报DatagramPacket,发信息和接收信息的是DatagramSocket。

 

TCP的socket有一个ServerSocket来负责监听宽口,Socket用来连接通信链路,信息是通过Socket和Socket建立I/O流来传递的。

UDP的socket有点像单向连接,没有通道,服务端和客户端是平等的,信息存在DatagramPacket数据报中,在其中指定IP和Port,直接send便可以了,目标DatagramSocket接收receive之后,把信息存入DatagramPacket,或者说 就是接收到一个DatagramSocket。

 

posted @ 2016-04-07 16:19  假寐的我  阅读(187)  评论(0编辑  收藏  举报