查看: 1762|回复: 0

[Java代码] java 网络编程之TCP通信和简单的文件上传功能实例

发表于 2018-2-25 08:00:00

TCP通信需要明确的几点:

tcp通信是面向连接的,需要先启动服务端,再启动客户端。

客户端和服务端都要创建套接字对象,客户端需要指定服务端套接字(ip+port),而服务端必须指定服务端口。

  1. Socket client_socket = new Socket("192.168.100.17",8888); //客户端套接字(Socket类的套接字为已连接套接字)
  2. ServerSocket listen_socket = new ServerSocket(8888); //服务端套接字,此时为监听套接字(已经bind()地址和端口了)
复制代码

服务端需要使用accept()方法将监听套接字转变为已连接套接字。这个监听套接字可以生成多个已连接套接字,这样连接后还能监听其他客户端的请求。因此,这里应该使用多线程实现并发访问。获得了已连接套接字,就可以获取很多客户端的信息,例如客户端的ip地址,发送请求的端口等。

  1. Socket server_scoket = socket.accept();
  2. Socket server_scoket2 = socket.accept();
  3. Socket server_scoket3 = socket.accept();
复制代码

服务端要实现并发连接,大致使用如下代码:其中ThreadTask是线程任务对象。

  1. public static void main(String[] args) throws IOException {
  2. ServerSocket listen_sock = new ServerSocket(8888); //监听套接字只需创建一个,因此在任务之外
  3. while (true) { //每建立一个连接,就开启一个线程
  4. Socket conn_sock = listen_sock.accept(); //没有新连接进来时,main主线程阻塞在此
  5. new Thread(new ThreadTask(conn_sock)).start();
  6. }
  7. }
复制代码

客户端需要根据已连接套接字获取输出流,服务端需要根据套接字获取输入流。当然,既然有了已连接套接字,那么获取无论哪一端都可以获取到输入流、输出流。

  1. OutputStream send_stream = client_socket.getOutputStream(); //客户端获取输出流
  2. InputStream recv_stream = server_socket.getInputStream();
复制代码

服务端应主动关闭已连接套接字,至于监听套接字则在合适的地方关闭。

服务端应该循环不断地负责接收。

简单的Client端:

  1. import java.io.IOException;
  2. import java.io.OutputStream;
  3. import java.net.Socket;
  4. public class TCPClient {
  5. public static void main(String[] args) {
  6. // 1.创建客户端套接字
  7. Socket c_sock = null;
  8. OutputStream client_outstream = null;
  9. try {
  10. c_sock = new Socket("192.168.0.124",8888);
  11. // 2.获取输出流
  12. client_outstream = c_sock.getOutputStream();
  13. // 3.输出数据
  14. client_outstream.write("Hello,i'm coming".getBytes());
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. } finally {
  18. if(c_sock != null){
  19. try{
  20. c_sock.close();
  21. } catch(IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }
  26. }
  27. }
复制代码

简单的Server端:

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.net.ServerSocket;
  6. import java.net.Socket;
  7. public class TCPServer {
  8. public static void main(String[] args) {
  9. // 1.创建监听套接字
  10. ServerSocket listen_sock = null;
  11. try {
  12. listen_sock = new ServerSocket(8888);
  13. } catch(IOException i) {
  14. i.printStackTrace();
  15. }
  16. Socket server_sock = null;
  17. InputStream in_sock = null;
  18. while (true) {
  19. try {
  20. // 2.和客户端建立连接,生成已连接套接字,并获取客户端ip地址
  21. server_sock = listen_sock.accept();
  22. String client_ip = server_sock.getInetAddress().getHostAddress();
  23. System.out.println("Client: " + client_ip + " connected");
  24. // 3.根据已连接套接字,获取输入流,读取客户端发送的数据
  25. in_sock = server_sock.getInputStream();
  26. BufferedReader bufr = new BufferedReader(new InputStreamReader(in_sock));
  27. String line = null;
  28. while ((line = bufr.readLine()) != null) {
  29. System.out.println(line);
  30. }
  31. // 4.关闭已连接套接字
  32. server_sock.close();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38. }
复制代码

以下是tcp实现文件上传功能:

客户端除了套接字的输出流,还有读取本地文件的输入流,还有套接字的输入流来读取来自服务端的反馈信息。

服务端也同样有三流:套接字的输入、输出流,写入上传目标文件的输出流。

客户端读取本地文件的所有数据后,需要使用套接字的shutdownOutput()来通知服务端套接字的输出流已到末尾。

服务端为了能为多人提供上传功能,需要使用多线程实现并发连接。

Client端:

  1. import java.io.BufferedReader;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.io.OutputStream;
  7. import java.net.Socket;
  8. public class UploadClient {
  9. public static void main(String[] args) {
  10. // TODO Auto-generated method stub
  11. String server_addr = "192.168.0.124";
  12. int server_port = 8888;
  13. Socket send_sock = null;
  14. FileInputStream local_read = null;
  15. try {
  16. // 1.客户端套接字
  17. send_sock = new Socket(server_addr, server_port);
  18. // 2.获取连接管道的输出流
  19. OutputStream send_stream = send_sock.getOutputStream();
  20. // 3.字节输入流读取本地文件数据,并使用套接字的输出流发送出去
  21. local_read = new FileInputStream("d:/myjava/net/SQL.docx");
  22. byte[] buf = new byte[1024];
  23. int len = 0;
  24. while ((len = local_read.read(buf)) != -1) {
  25. send_stream.write(buf, 0, len);
  26. }
  27. // 4.标记输出流到结尾
  28. send_sock.shutdownOutput();
  29. // 5.接收服务端的反馈数据,如上传成功,上传失败等
  30. InputStream recv_stream = send_sock.getInputStream();
  31. BufferedReader ack_recv = new BufferedReader(new InputStreamReader(recv_stream));
  32. String line = null;
  33. while ((line = ack_recv.readLine()) != null) {
  34. System.out.println(line);
  35. }
  36. } catch (IOException i) {
  37. i.printStackTrace();
  38. } finally {
  39. if (send_sock != null) {
  40. try {
  41. send_sock.close();
  42. local_read.close();
  43. } catch (IOException i1) {
  44. i1.printStackTrace();
  45. }
  46. }
  47. if (local_read != null) {
  48. try {
  49. local_read.close();
  50. } catch (IOException i2) {
  51. i2.printStackTrace();
  52. }
  53. }
  54. }
  55. }
  56. }
复制代码

Server端:

  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.OutputStream;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. public class UploadServer {
  9. public static void main(String[] args) throws IOException {
  10. ServerSocket listen_sock = new ServerSocket(8888); //监听套接字只需创建一个,因此在任务之外
  11. while (true) { //每建立一个连接,就开启一个线程
  12. Socket conn_sock = listen_sock.accept(); //没有新连接进来时,main主线程阻塞在此
  13. new Thread(new Uploader(conn_sock)).start();
  14. }
  15. }
  16. }
  17. class Uploader implements Runnable {
  18. private File dest_dir = new File("d:/temp"); // 上传目录
  19. private Socket conn_sock = null; // 连接套接字
  20. InputStream recv_stream = null;
  21. FileOutputStream dest_stream = null;
  22. Uploader(Socket conn_sock) throws IOException {
  23. this.conn_sock = conn_sock;
  24. }
  25. public void run() {
  26. try {
  27. if (!dest_dir.exists()) {
  28. dest_dir.mkdirs();
  29. }
  30. // 1.获取连接管道的输入流
  31. recv_stream = conn_sock.getInputStream();
  32. // 客户端ip
  33. String client_ip = conn_sock.getInetAddress().getHostAddress();
  34. System.out.println(client_ip + ".....connected");
  35. // 2.文件的上传位置,即输出目标,以ip命名。如果文件已存在,则使用括号加数字新建文件,如"192.168.100.23(1).txt"
  36. File dest_file = new File(dest_dir, client_ip + ".docx");
  37. int count = 1;
  38. while (dest_file.exists()) {
  39. dest_file = new File(dest_dir, client_ip + "(" + count + ")" + ".docx");
  40. count++;
  41. }
  42. // 3.读取数据并写入目标文件
  43. dest_stream = new FileOutputStream(dest_file);
  44. byte[] buf = new byte[1024];
  45. int len = 0;
  46. while ((len = recv_stream.read(buf)) != -1) {
  47. dest_stream.write(buf, 0, len);
  48. }
  49. // 4. 向客户端反馈信息
  50. OutputStream ack_send = conn_sock.getOutputStream();
  51. byte[] text = "upload successful!".getBytes();
  52. ack_send.write(text);
  53. } catch (IOException e1) {
  54. e1.printStackTrace();
  55. } finally {
  56. if (dest_stream != null) {
  57. try {
  58. dest_stream.close();
  59. } catch (IOException i) {
  60. i.printStackTrace();
  61. }
  62. }
  63. if (conn_sock != null) {
  64. try {
  65. conn_sock.close();
  66. } catch (IOException i) {
  67. i.printStackTrace();
  68. }
  69. }
  70. }
  71. }
  72. }
复制代码

以上这篇java 网络编程之TCP通信和简单的文件上传功能实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持程序员之家。



回复

使用道具 举报