概念
Socket 又被称为“套接字”。有一个层叫传输层,传输层的作用:将上三层的数据 和下三层的数据进行 转换
套接字:实际上就是咱们传输层用来传输数据的 一种载体 (通道),包括IP和端口
套接字编程

使用其中的哪些类取决于程序所需处理的通讯协议。例如,基于TCP的应用程序可使用 Socket、ServerSocket 等类;基于UDP的应用程序则使用DatagramPacket、DatagramSocket、MulticastSocket 等类;基于 HTTP 和 FTP 等协议直接访问 URL 资源的应用程序可使用 URL、URLConnection 等类。
一个简单的实例
我们需要建立一个服务器类和一个客户端类,实现一个简单的功能:客户端向服务端发送消息
服务器类:
/*** TCP/IP协议的服务端(代码)** @author Administrator**/public class SocketServerStudy {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println("主线程启动!!!!!");ServerSocket server = null;try {//创建Socket 的服务端,并指定8080 为通讯端口server = new ServerSocket(8080);//接收客户端(该方法是个阻塞式方法)Socket socket = server.accept();//输入流InputStream in = socket.getInputStream();//转换流InputStreamReader isr = new InputStreamReader(in,"UTF-8");//缓冲流BufferedReader br = new BufferedReader(isr);//边读边响应String str = "";while((str = br.readLine()) != null) {System.out.println("服务器接收的数据是:" + str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
客户端类:
public class SocketClientStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
//本机使用127.0.0.1 或者 localhost
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 8080);
//建立传输流
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
//向服务端发送数据
bw.write("这是一个TCP/IP的测试信息!!!!");
bw.flush();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bw.close();
osw.close();
os.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结:
1、此例子实现了单服务器与单客户端之间的连接
2、服务器使用的I/O流,本质上是由客户端类进行提供
3、在连接时,客户端需要明确服务器的IP地址和端口号,服务器只需要向操作系统申请一个端口号即可
4、本机的IP地址可以表示为:127.0.0.1或者localhost
案例—单服务器连接多客户端
要实现这个功能很简单,只需要把Socket socket = server.accept();代码和下方的代码加入一个While死循环即可,每连接上一个客户端,就会创建一个新的Socket实例,客户端和客户端之间不冲突
public class SocketServerStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("主线程启动!!!!!");
ServerSocket server = null;
try {
//创建Socket 的服务端,并指定8080 为通讯端口
server = new ServerSocket(8080);
while(true) {
//接收客户端(该方法是个阻塞式方法)
Socket socket = server.accept();
//输入流
InputStream in = socket.getInputStream();
//转换流
InputStreamReader isr = new InputStreamReader(in,"UTF-8");
//缓冲流
BufferedReader br = new BufferedReader(isr);
//边读边响应
String str = "";
while((str = br.readLine()) != null) {
System.out.println("服务器接收的数据是:" + str);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
案例—结合线程的知识,实现读写任务的分离
要实现这个功能,我们需要把读写的任务分别作为线程的任务进行封装,在服务器端只需要开启线程即可
服务器:
/**
* TCP/IP协议的服务端(代码)
*
* @author Administrator
*
*/
public class SocketServerStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("主线程启动!!!!!");
ServerSocket server = null;
try {
// 创建Socket 的服务端,并指定8080 为通讯端口
server = new ServerSocket(8080);
while (true) {
// 接收客户端(该方法是个阻塞式方法)
Socket socket = server.accept();
//定义一个传输队列(FIFO)
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);
// 读
Thread t1 = new Thread(new ServerReaderTask(socket,queue));
t1.start();
// 写
Thread t2 = new Thread(new ServerWriterTask(socket,queue));
t2.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
读取任务:
/**
* 服务端的 读取任务
*
* @author Administrator
*
*/
public class ServerReaderTask implements Runnable {
/**
* 代表连接通道
*/
private Socket socket;
/**
* 数据传输通道
*/
private ArrayBlockingQueue<String> queue;
public ServerReaderTask(Socket socket, ArrayBlockingQueue<String> queue) {
super();
this.socket = socket;
this.queue = queue;
}
@Override
public void run() {
// TODO Auto-generated method stub
// 输入流
InputStream in = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
if(!socket.isClosed() && socket.isConnected()) {
// 获得客户端的IP地址
String hostName = socket.getInetAddress().getHostName();
System.out.println(hostName);
in = socket.getInputStream();
// 转换流
isr = new InputStreamReader(in, "UTF-8");
// 缓冲流
br = new BufferedReader(isr);
// 读取消息
String str = "";
while (!(str = br.readLine()).equals("END")) {
System.out.println("服务器接收[" + hostName + "]的消息:" + str);
}
queue.add("[" + hostName + "] 的消息,我已收到!!!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
if(e instanceof SocketException) {
System.out.println("该连接已被重置!!!!");
}
}
}
}
写入任务:
/**
* 服务端的 写入任务
*
* @author Administrator
*
*/
public class ServerWriterTask implements Runnable {
/**
* 代表连接通道
*/
private Socket socket;
/**
* 数据传输通道
*/
private ArrayBlockingQueue<String> queue;
public ServerWriterTask(Socket socket, ArrayBlockingQueue<String> queue) {
super();
this.socket = socket;
this.queue = queue;
}
@Override
public void run() {
// TODO Auto-generated method stub
//建立传输流
OutputStream os = null;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
if(!socket.isClosed() && socket.isConnected()) {
os = socket.getOutputStream();
osw = new OutputStreamWriter(os, "UTF-8");
bw = new BufferedWriter(osw);
while(!queue.isEmpty()) {
bw.write(queue.poll());
bw.newLine();
}
bw.flush();
}
} catch (Exception e) {
// TODO Auto-generated catch block
if(e instanceof SocketException) {
System.out.println("该连接已被重置!!!!");
}
}
}
}
客户端:
public class SocketClientStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 本机使用127.0.0.1 或者 localhost
Socket socket = null;
// 建立传输流
OutputStream os = null;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
socket = new Socket("127.0.0.1", 8080);
if (!socket.isClosed() && socket.isConnected()) {
os = socket.getOutputStream();
osw = new OutputStreamWriter(os, "UTF-8");
bw = new BufferedWriter(osw);
for(int i = 0; i < 10; i ++) {
System.out.println("客户端输出:" + i);
Thread.sleep(2000);
bw.write("长江,长江,我是黄河!!!!");
bw.newLine();
}
bw.write("END");
bw.newLine();
}
bw.flush();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (!socket.isClosed() && socket.isConnected()) {
try {
bw.close();
osw.close();
os.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
