基于Socket的TCP编程

Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示: image.png


客户端Socket的工作过程的四个基本的步骤

创建 Socket:
根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
打开连接到 Socket 的输入/出流:
使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
按照一定的协议对 Socket 进行读/写操作:
通过输入流读取服务器放入线路的信息 (但不能读取自己放入线路的信息),通过输出流将信息写入线程。
关闭 Socket:
断开客户端到服务器的连接,释放线路

注意事项

  • 客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接。Socket的构造器是:

Socket(String host,int port)throws UnknownHostException,IOException
向服务器(域名是 host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
Socket(InetAddress address,int port)throws IOException
根据InetAddress对象所表示的 IP地址以及端口号port发起连接。

  1. public void client() {
  2. Socket socket = null;
  3. OutputStream os = null;
  4. try {
  5. //1.创建Socket对象,指明服务器端的ip和端口号
  6. InetAddress inet = InetAddress.getByName("192.168.14.100");
  7. socket = new Socket(inet,8899);
  8. //2.获取一个输出流,用于输出数据
  9. os = socket.getOutputStream();
  10. //3.写出数据的操作
  11. os.write("你好,我是客户端mm".getBytes());
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. } finally {
  15. //4.资源的关闭
  16. if(os != null){
  17. try {
  18. os.close();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. if(socket != null){
  24. try {
  25. socket.close();
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }

服务器程序工作过程的四个基本的步骤

调用 ServerSocket(int port)
创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。
调用 accept():
监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
调用该Socket类对象的 getOutputStream() 和 getInputStream ():
获取输出流和输入流,开始网络数据的发送和接收。
关闭ServerSocket和Socket对象:
客户端访问结束,关闭通信套接字。

使用说明

  • ServerSocket 对象负责等待客户端请求建立套接字连接。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的ServerSocket对象。
  • 所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象

    1. public void server() {
    2. ServerSocket ss = null;
    3. Socket socket = null;
    4. InputStream is = null;
    5. ByteArrayOutputStream baos = null;
    6. try {
    7. //1.创建服务器端的ServerSocket,指明自己的端口号
    8. ss = new ServerSocket(8899);
    9. //2.调用accept()表示接收来自于客户端的socket
    10. socket = ss.accept();
    11. //3.获取输入流
    12. is = socket.getInputStream();
    13. //不建议这样写,可能会有乱码
    14. // byte[] buffer = new byte[1024];
    15. // int len;
    16. // while((len = is.read(buffer)) != -1){
    17. // String str = new String(buffer,0,len);
    18. // System.out.print(str);
    19. // }
    20. //4.读取输入流中的数据
    21. baos = new ByteArrayOutputStream();
    22. //ByteArrayOutputStream 是字节数组输出流。它继承于OutputStream。
    23. //ByteArrayOutputStream 中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。
    24. //可使用 toByteArray() 和 toString() 获取数据。
    25. byte[] buffer = new byte[5];
    26. int len;
    27. while((len = is.read(buffer)) != -1){//将数据读入到buffer数组
    28. baos.write(buffer,0,len);//将buffer数组写出到baos
    29. }
    30. System.out.println(baos.toString());
    31. System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据");//获取此 IP 地址的主机名
    32. } catch (IOException e) {
    33. e.printStackTrace();
    34. } finally {
    35. if(baos != null){
    36. //5.关闭资源
    37. try {
    38. baos.close();
    39. } catch (IOException e) {
    40. e.printStackTrace();
    41. }
    42. }
    43. if(is != null){
    44. try {
    45. is.close();
    46. } catch (IOException e) {
    47. e.printStackTrace();
    48. }
    49. }
    50. if(socket != null){
    51. try {
    52. socket.close();
    53. } catch (IOException e) {
    54. e.printStackTrace();
    55. }
    56. }
    57. if(ss != null){
    58. try {
    59. ss.close();
    60. } catch (IOException e) {
    61. e.printStackTrace();
    62. }
    63. }
    64. }

  1. /**
  2. * 实现TCP的网络编程
  3. * 例题3:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。
  4. * 并关闭相应的连接。
  5. * @author shkstart
  6. * @create 2019 下午 4:13
  7. */
  8. public class TCPTest{
  9. /*
  10. 这里涉及到的异常,应该使用try-catch-finally处理
  11. */
  12. @Test
  13. public void client() throws IOException {
  14. //1.
  15. Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
  16. //2.
  17. OutputStream os = socket.getOutputStream();
  18. //3.
  19. FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
  20. //4.
  21. byte[] buffer = new byte[1024];
  22. int len;
  23. while((len = fis.read(buffer)) != -1){
  24. os.write(buffer,0,len);
  25. }
  26. //关闭数据的输出
  27. socket.shutdownOutput();
  28. //5.接收来自于服务器端的数据,并显示到控制台上
  29. InputStream is = socket.getInputStream();
  30. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  31. byte[] bufferr = new byte[20];
  32. int len1;
  33. while((len1 = is.read(buffer)) != -1){
  34. baos.write(buffer,0,len1);
  35. }
  36. System.out.println(baos.toString());
  37. //6.
  38. fis.close();
  39. os.close();
  40. socket.close();
  41. baos.close();
  42. }
  43. /*
  44. 这里涉及到的异常,应该使用try-catch-finally处理
  45. */
  46. @Test
  47. public void server() throws IOException {
  48. //1.
  49. ServerSocket ss = new ServerSocket(9090);
  50. //2.
  51. Socket socket = ss.accept();
  52. //3.
  53. InputStream is = socket.getInputStream();
  54. //4.
  55. FileOutputStream fos = new FileOutputStream(new File("beauty2.jpg"));
  56. //5.
  57. byte[] buffer = new byte[1024];
  58. int len;
  59. while((len = is.read(buffer)) != -1){
  60. fos.write(buffer,0,len);
  61. }
  62. System.out.println("图片传输完成");
  63. //6.服务器端给予客户端反馈
  64. OutputStream os = socket.getOutputStream();
  65. os.write("你好,美女,照片我已收到,非常漂亮!".getBytes());
  66. //7.
  67. fos.close();
  68. is.close();
  69. socket.close();
  70. ss.close();
  71. os.close();
  72. }
  73. }