转载 自 http://blog.51cto.com/13501268/2092179
Scoket(套接字)
1. 两个应用程序可以通过一个双向的网络通信连接实现数据交换,这个双 向链接的一端称为一个Scoket
2. Scoket可以看成两个程序进行通讯连接 中的一个端点,一个程序将一个 信息写入Scoket中,该Scoket将这段信息发送给另外一个Scoket中, 使这段信息能传送到其他程序中
3. Scoket通常用来实现client-server(客户端—服务端)连接,建立连接时 所需要的寻址信息为远程计算机的IP地址和端口号(Port Number)
4. 网络编程的四个基本步骤
(1)创建scoket;
(2)打开连接到scoket的输入输出流/输出流(通过Scoket的 getInputStream()和getOutputStream());
(3)按照一定的协议对scoket进行读写/写操作;
(4)关闭scoket;
5. 基于TCP协议的Scoket编程
(1)基于TCP协议的scoket的网络通信
<1>用来实现双向安全连接网络通信
<2>TCP Scoket通常用来实现client-server连接,建立连接时所 需要的寻址信息为远程计算机的IP地址和端口号(Port Number)
(2) TCP Scoket通信模型:进行网络通信时,Socket需要借助数据流来完成数据的传递工作
6.TCP通信原理
例1. (实现服务端与客户端连接)
建立服务端:
package scoket;
import java.io.*;
import java.net.*;
public class Server {
/* 编写服务器
*/
public static void main(String[] args) {
ServerSocket server=null;
Socket socket=null;
OutputStream out=null;
try {
server=new ServerSocket(9999);//创建服务器,并规定端口号为9999
System.out.println("等待服务器连接..");
socket=server.accept();//监听服务器连接,连接之前一直阻塞
out=socket.getOutputStream();//获取Socket输出流,用来与他连接的服务器写入
out.write("你好,Socket编程!!!".getBytes());//向输出流中写入内容,用getBytes()转化为字节数组
System.out.println("发送成功...");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
server.close();//关闭服务器
socket.close();//关闭socket
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
建立客户端:
package scoket;
import java.io.*;
import java.net.*;
/*
* 编写客户端
*/
public class Client {
public static void main(String[] args){
Socket socket=null;
InputStream input=null;
try {
socket=new Socket("localhost",9999);//连接到服务器,localhost本机
input=socket.getInputStream();//获取socket输入流,用于获取服务器发送的信息
byte[] b=new byte[1024];//建立字节数组缓冲区
int len=input.read(b);//读取字节数组
System.out.println("获取到的服务器信息为:"+new String(b,0,len));//将获取到的信息转化为字符串
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果为(运行时先启动服务端再启动客户端):
服务端:
等待服务器连接..
发送成功...
客户端:
获取到的服务器信息为:你好,Socket编程!!!
例2(将输入输出流进行装饰):
服务端:
package decorator;
import java.io.*;
import java.net.*;
/*
* 服务端
*/
public class Server {
public static void main(String[] args) {
ServerSocket server=null;
Socket socket=null;
try {
server=new ServerSocket(9999);//创建服务端,并规定端口号
System.out.println("客户端开始连接...");
socket=server.accept();//监听客户端,连接之前 一直阻塞
PrintStream ps=new PrintStream(socket.getOutputStream());//获取socket输出流,并封装到PrintStream输出流中;
ps.println("通过PrintStream发送信息...");//利用println()向客户端发送信息
System.out.println("服务器信息发送完毕...");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
server.close();//关闭服务器资源
socket.close();//关闭socket
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
package decorator;
import java.io.*;
import java.net.*;
/*
* 客户端
*/
public class Client {
public static void main(String[] args){
Socket socket=null;
InputStream input=null;
try {
socket=new Socket("localhost", 9999);//创建客户端 ,并建立连接
//将socket输入流封装到BufferedReader中
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str=br.readLine();//利用readLine()读取接收到的服务端信息
System.out.println("客户端:"+str);
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
socket.close();//关闭socket资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:
客户端开始连接...
服务器信息发送完毕...
客户端:通过PrintStream发送信息...
例2. (模仿反响机制echo)
服务端线程类:
package echo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/*
* 服务端线程类
*/
public class ECHORunnable implements Runnable{
private Socket socket;
public ECHORunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//获取输入流,用于读取客户端信息,用BufferedReader包装
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//获取输出流用于向客户端发送信息,用PrintStream包装
PrintStream ps=new PrintStream(socket.getOutputStream());
//与客户端不断交互,直到客户端说‘bye’时退出与客户端交互
while(true){
String str=br.readLine();//读取客户端发送来胡信息
ps.println(str);
if(str.equals("bye")){
socket.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端:
package echo;
/*
* 服务端
*/
import java.io.IOException;
import java.net.*;
public class Server {
public static void main(String[] args) {
ServerSocket server=null;
Socket socket=null;
try {
server=new ServerSocket(9999);//创建服务端并规定端口号为9999
boolean flag=true;
int count=0;
while(flag){
count++;
System.out.println("服务器与第"+count+"位客户端连接.....");
socket=server.accept();//监听客户端连接
new Thread(new ECHORunnable(socket)).start();//开启服务端线程
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
package echo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端
*/
public class Client {
public static void main(String[] args) {
BufferedReader keybr=new BufferedReader(new InputStreamReader(System.in));
Socket socket=null;
try {
socket=new Socket("localhost",9999);//连接本地服务端
PrintStream ps=new PrintStream(socket.getOutputStream());//获取输出流,用于向客户端发送信息
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流用于读取服务端返回胡信息
while(true){
System.out.println("白雪公主:");
String revice=keybr.readLine();//读取键盘输入
ps.println(revice);//发送客户端信息
String str=br.readLine();//获取服务端信息
System.out.println("青蛙王子:"+str);
if("bye".equals(revice)){
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
白雪公主:
你好
青蛙王子:你好
白雪公主:
你在干啥
青蛙王子:你在干啥
白雪公主:
bye
青蛙王子:bye
例4(C-S传图片):
服务端线程类:
package binary;
import java.io.*;
import java.net.Socket;
// 上传线程类
public class UploadRunnable implements Runnable{
private Socket socket;
public UploadRunnable(Socket socket){
this.socket=socket;
}
@Override
public void run() {
OutputStream out=null;
try {
InputStream input=socket.getInputStream(); // 用此来接收客户端发来的内容
String fileName=System.currentTimeMillis()+".jpg";
out=new FileOutputStream("d:"+File.separator+"upload"+File.separator+fileName); // 用来写入服务器中的输出流
byte[] b=new byte[1024];
int len=0;
// 循环从客户端读,写入服务器端
while((len=input.read(b))!=-1){
out.write(b, 0, len);
}
System.out.println(Thread.currentThread().getName()+"写入成功!");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务端:
package binary;
import java.io.IOException;
import java.net.*;
// 服务端
public class Server {
public static void main(String[] args) {
ServerSocket server=null;
try {
server=new ServerSocket(8888);
int count=0;
while(true){
count++;
System.out.println("等待第"+count+"位客户连接...");
Socket socket=server.accept(); // 监听客户端连接,连接之前一直阻塞
new Thread(new UploadRunnable(socket)).start(); // 启动线程,在线程中与客户端交互
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
package binary;
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
Socket socket=null;
InputStream input=null;
try {
socket=new Socket("localhost",8888);
input=new FileInputStream("d:"+File.separator+"images"+File.separator+"bingfa.jpg");
OutputStream out=socket.getOutputStream(); // 用来向服务端不断写入
byte[] b=new byte[1024];
int len=0;
// 从客户端磁盘上读,不断写入服务端
while((len=input.read(b))!=-1){
out.write(b,0,len);
}
System.out.println("客户端上传成功!");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
input.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}