参考资料:
http://haohaoxuexi.iteye.com/blog/1979837
http://zhidao.baidu.com/link?url=OeOSa0YbOzSbMVPa8sgPXcwtyyHsWB1lPkh1XopETtNK_lVtbd9lL7NH3qlFxjC-4kNUmCkIXgcfRW7KJq9_FK
http://www.cnblogs.com/rond/p/3565113.html
http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html
TCP/IP客户套接字
Java中有两种类型的TCP套接字,一种用于服务器,一种用于客户端。
ServerSocket类型设计成“监听器”,等待客户端连接的到来。因此,ServerSocket用于服务器。
Socket类用于客户端,它被设计成连接服务器套接字并且初始化协议的交换。
图片来自:http://www.cnblogs.com/rond/p/3565113.html
Socket
Socket可以使客户程序与服务器程序通信,使用Socket连接服务器的过程包含以下4个基本的步骤
(1)创建Socket
(2)打开连接到Socket的输入/输出流
(3)按照一定协议对Socket执行读写操作
(4)关闭Socket
Socket()
boolean isConnection=socket.isConnected() && !socket.isClosed(); //判断当前是否处于连接
半关闭Socket
- 自定义标识符(譬如下面的例子,当受到“bye”字符串的时候,关闭Socket)
- 告知读取长度(有些自定义协议的,固定前几个字节表示读取的长度的)
- 读完所有数据
- 当Socket调用close的时候关闭的时候,关闭其输入输出流
例:
public class TestPort { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub String hostname = "www.baidu.com"; InetAddress addr = InetAddress.getByName(hostname); Socket so = new Socket(addr,80); System.out.println("远程连接地址:"+so.getInetAddress()); System.out.println("远程连接端口:"+so.getPort()); System.out.println("本地连接地址:"+so.getLocalAddress()); System.out.println("本地连接端口:"+so.getLocalPort()); InputStream is = so.getInputStream(); /* * 这部分为客户端操作,需要一台远程服务器 int c; while((c=is.read())!=-1){ System.out.println("gas"); }*/ is.close(); so.close(); } }
运行结果:
远程连接地址:www.baidu.com/119.75.218.70 远程连接端口:80 本地连接地址:/192.168.1.160 本地连接端口:4338
public class GetServerIP { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub InetAddress addr =InetAddress.getByName("localhost"); ServerSocket se = new ServerSocket(10000,10,addr); System.out.println(se.getInetAddress()); System.out.println(se.getLocalPort()); } }
运行结果
localhost/127.0.0.1 10000
附:完整例子
发送端 socket
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class SocketSender { public static void main(String[] args) { Socket socket = null; try { socket = new Socket("127.0.0.1", 27401); // 向服务端发送信息 OutputStream outer = socket.getOutputStream(); byte[] b = "客户端:向服务端发送文字,\"这是一行测试....\"".getBytes(); outer.write(b); outer.flush(); System.out.println("发送完毕!"); // 接收服务端的返回值 InputStream inner = socket.getInputStream(); int count = 0; while (count == 0) { count = inner.available(); } byte[] recv = new byte[count]; inner.read(recv); String str_recv = new String(recv); System.out.println("客户端:接收到服务端的文字:" + str_recv); } catch (IOException e) { System.out.println("发送端出现异常"); } finally { if (socket != null) try { socket.close(); } catch (IOException e) { System.out.println("发送端 finally 出现异常"); } } } }
接收端:ServerSocket
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class SocketReceiver { public static void main(String[] args) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(27401); while (true) { Socket socket = serverSocket.accept(); // 接收客户端的信息 InputStream in = socket.getInputStream(); int count = 0; while (count == 0) { count = in.available(); } byte[] b = new byte[count]; in.read(b); String str = new String(b); System.out.println(str); // 向客户端发送确认消息 OutputStream outer = socket.getOutputStream(); byte[] b_out = "已经收到,返回消息码200".getBytes(); outer.write(b_out); outer.flush(); // 关闭socket socket.close(); } } catch (IOException e) { System.out.println("接收端出现异常"); } finally { if (serverSocket != null) try { serverSocket.close(); } catch (IOException e) { System.out.println("接收端 finally 出现异常"); } } } }
接收端:方法2,利用多线程,每一个发送端对应接收端的一个线程
public class SocketReceiverWithThread { public static void main(String[] args) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(27401); while (true) { Socket socket = serverSocket.accept(); new Thread(new Handler(socket)).start(); //socket.close(); 注意 关闭socket不能在这里,而应该写在线程内,否则可能线程没结束就关闭了socket } } catch (IOException e) { System.out.println("接收端出现异常"); } finally { if (serverSocket != null) try { serverSocket.close(); } catch (IOException e) { System.out.println("接收端 finally 出现异常"); } } } } class Handler implements Runnable { private Socket socket; public Handler(Socket socket) { this.socket = socket; } public void run() { try { // 接收客户端的信息 InputStream in = socket.getInputStream(); int count = 0; while (count == 0) { count = in.available(); } byte[] b = new byte[count]; in.read(b); String str = new String(b); System.out.println(str); // 向客户端发送确认消息 OutputStream outer = socket.getOutputStream(); byte[] b_out = "已经收到,返回消息码200".getBytes(); outer.write(b_out); outer.flush(); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭socket try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
附2:使用socket进行文件传送
客户端 ClienPart.java

package com.client; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.Socket; public class ClientPart { private Socket socket=null; private String ip ;// 设置成服务器IP private int port ; public ClientPart(String ip,int port) { this.ip=ip; this.port=port; } private boolean createConnection() { try { socket = new Socket(ip, port); System.out.print("连接服务器成功!" + "\n"); return true; } catch (Exception e) { e.printStackTrace(); return false; } } //向服务器发送消息 private void sentMessage(String msg){ if (socket == null) return; Writer writer; try { writer = new OutputStreamWriter(socket.getOutputStream()); writer.write(msg); writer.flush(); //写完后要记得flush writer.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } private void getFile() { if (socket == null) return; DataInputStream inputStream = null; try { inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream())); } catch (Exception e) { System.out.print("接收消息缓存错误\n"); return; } try { //本地保存路径,文件名会自动从服务器端继承而来。 String savePath = "F:\\client\\"; int bufferSize = 8192; byte[] buf = new byte[bufferSize]; long len=0; savePath += inputStream.readUTF(); //读取文件名 DataOutputStream fileOut = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(savePath)))); len = inputStream.readLong(); //读取文件长度 System.out.println("文件的长度为:" + len); System.out.println("开始接收文件!"); while (true) { int read = 0; if (inputStream != null) { read = inputStream.read(buf); } if (read == -1) { break; } //客户端读出文件 fileOut.write(buf, 0, read); } System.out.println("接收完成,文件存为" + savePath + "\n"); fileOut.close(); socket.close(); } catch (Exception e) { System.out.println("接收消息错误" + "\n"); return; } } private void putFile(String filename){ String filePath = filename; File client_file = new File(filePath); //要传输的文件路径 long filelen = client_file.length(); System.out.println("要上传的文件长度:" + (int)filelen); try{ DataInputStream in_stream = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); DataOutputStream out_stream = new DataOutputStream(socket.getOutputStream()); out_stream.writeUTF(client_file.getName()); out_stream.flush(); out_stream.writeLong((long) client_file.length()); out_stream.flush(); int bufferSize = 8192; byte[] buf = new byte[bufferSize]; while (true) { int read = 0; if (in_stream != null) { read = in_stream.read(buf); } if (read == -1) { break; } out_stream.write(buf, 0, read); } out_stream.flush(); // 注意关闭socket链接,不然客户端会等待server的数据过来, // 直到socket超时,会导致数据不完整。 in_stream.close(); socket.close(); System.out.println("文件传输完成"); }catch(Exception e){ e.printStackTrace(); } } public static void main(String arg[]) { ClientPart client = new ClientPart("127.0.0.1",7005); client.createConnection(); client.sentMessage("read");//向服务器发送信息,说明需要读取文件 client.createConnection(); client.getFile(); //获取服务器发送的文件 client.createConnection(); client.sentMessage("write");//向服务器发送信息,说明需要上传文件 client.createConnection(); client.putFile("F:\\client\\1.txt");//向服务器发送文件 } }
服务端 ServerPart.java

package com.server; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.ServerSocket; import java.net.Socket; public class ServerPart { int port = 7005; public void serverStart() { try { ServerSocket ssocket = new ServerSocket(port); System.out.println("服务器准备完毕!"); while (true) { String msg = checkIO(ssocket); //获取来自客户端的请求是读/写 if(msg.compareTo("read")==0){ sendFile(ssocket); //向客户端发送文件 } else if(msg.compareTo("write")==0){ saveFile(ssocket); //存储来自客户端的文件 } } } catch (Exception e) { e.printStackTrace(); } } //服务器检查来自客户端的请求是读/写 public String checkIO(ServerSocket ssocket) throws IOException{ Socket socket=ssocket.accept(); Reader reader = new InputStreamReader(socket.getInputStream()); char chars[] = new char[10]; int len; StringBuilder sb = new StringBuilder(); while ((len=reader.read(chars)) != -1) { sb.append(new String(chars, 0, len)); } reader.close(); socket.close(); return sb.toString(); } public void sendFile(ServerSocket ssocket) throws IOException{ Socket soc = null; // 选择进行传输的文件 String filePath = "F:\\server\\info.bin"; File myfile = new File(filePath); System.out.println("服务器文件长度:" + (int) myfile.length()); soc = ssocket.accept(); System.out.println("建立socket链接"); DataInputStream in_stream = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); DataOutputStream out_stream = new DataOutputStream(soc.getOutputStream()); //将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java 4th里有现成的代码。 out_stream.writeUTF(myfile.getName()); out_stream.flush(); out_stream.writeLong((long) myfile.length()); out_stream.flush(); int bufferSize = 8192; byte[] buf = new byte[bufferSize]; while (true) { int read = 0; if (in_stream != null) { read = in_stream.read(buf); } if (read == -1) { break; } out_stream.write(buf, 0, read); } out_stream.flush(); // 注意关闭socket链接哦,不然客户端会等待server的数据过来, // 直到socket超时,导致数据不完整。 out_stream.close(); in_stream.close(); soc.close(); System.out.println("服务器文件传输完成"); } //服务器保存文件的方法 public void saveFile(ServerSocket ssocket) throws IOException{ Socket soc = ssocket.accept(); if (soc == null) return; DataInputStream inputStream = null; try { inputStream = new DataInputStream(new BufferedInputStream(soc.getInputStream())); } catch (Exception e) { System.out.print("服务器接收消息缓存错误\n"); return; } try { //服务器文件的保存路径 String savePath = "f:\\server\\"; int bufferSize = 8192; byte[] buf = new byte[bufferSize]; long len=0; savePath += inputStream.readUTF(); //读取文件名 DataOutputStream fileOut = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(savePath)))); len = inputStream.readLong(); //读取文件长度 //控制台输出 System.out.println("文件的长度为:" + len); System.out.println("开始接收文件!"); while (true) { int read = 0; if (inputStream != null) { read = inputStream.read(buf); } if (read == -1) { break; } //客户端读出文件 fileOut.write(buf, 0, read); } System.out.println("接收完成,文件存为" + savePath + "\n"); fileOut.close(); soc.close(); } catch (Exception e) { System.out.println("接收消息错误" + "\n"); e.printStackTrace(); return; } } public static void main(String arg[]) { //启动服务器 new ServerPart().serverStart(); } }