Socket网络编程

Socket网络编程

网络模型

1. OSI(开放系统互连)参考模型
     分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
2. TCP/IP参考模型
   	  分为:应用层、                        、传输层、网际层、主机至网络层

网络通讯三要素

1. IP地址     网络中的标识,本地回路地址127.0.0.1  主机名localhost
2. 端口号     用于标识进程的逻辑地址  有效端口 0--655365     0--1024系统使用或保留端口
3. 传输协议    &nbsp通讯的规则,常见的有
   - TCP(分装数据包,无需建立连接,大小限制在64k内,不可靠,速度快)
   - UDP(建立连接形成传输通道,进行大量数据传输,三次握手安全可靠,效率稍低)
     (三次握手:1在没在 2在 3我知道了)

获取IP地址对象

1. 获取本机主机IP地址对象 
   `InetAddress ip = InetAddress.getLocalHost();`
2. 获取其他主机IP地址对象(192.168.xxx.255是广播)
   - `String ip = "192.168.4.16";`
     `String[] ip_split = ip.split("\\.");`
         `int i = 0;`
         `byte[] bytes = new byte[4];`
         `bytes[0] = (byte)Integer.parseInt(ip_split[0]);`
         `bytes[1] = (byte)Integer.parseInt(ip_split[1]);`
         `bytes[2] = (byte)Integer.parseInt(ip_split[2]);`
         `bytes[3] = (byte)Integer.parseInt(ip_split[3]);`
     `InetAddress ip = InetAddress.getByAddress(bytes) ;`
   - `InetAddress ip = InetAddress.getByName("主机名/IP地址");`
   - `InetAddress[] ip = InetAddress.getAllByName("主机名/IP地址");`部分网址有多个ip地址,此方法返回对象数组
      			`ip.getHostAddress()`   获取IP地址
      			`ip.getHostName()`      获取主机名
public static void main(String[] args) throws UnknownHostException {
  	//获取本机主机IP地址对象
  	InetAddress ip = InetAddress.getLocalHost();
  	
  	System.out.println(ip.getHostAddress());
  	System.out.println(ip.getHostName());
  	
  	//获取其他主机IP地址对象
  	ip = InetAddress.getByName("DESKTOP-MLPB9BK");
  	System.out.println(ip.getHostAddress());
  	System.out.println(ip.getHostName());
  	
  	ip = InetAddress.getByName("www.baidu.com");
  	System.out.println(ip.getHostAddress());
  	System.out.println(ip.getHostName());
  }

DNS 域名解析服务器,存储了IP与域名的对应关系

Socket是为网络服务提供的一种机制。通信两端都有Socket.网络通信就是Socket之间的通信,数据在两Socket间通过IO传输

UDP协议传输

UDP 对应Socket对象 DatagramSocket

  • 发送端

    1. 创建UDP的Socket服务,(是否指定端口号均可)
      DatagramSocket ds = new DatagramSocket([端口号,可有可无]);
    2. 将要发送到数据封装到数据包中
      byte[] buf = "UDP传输演示,发送端数据".getBytes();
      DatagramPacket dp = new DatagramPacket(byte[],byte[].length, InetAddress.getLocalHost(), 9999);
    3. 通过UDP的Socket服务的send()方法将数据包发送
      ds.send(dp);
    4. 关闭Socket服务
      ds.close();
  • 接收端

    1. 建立Socket服务,因是接收数据,必须要绑定端口与发送方数据包指定的端口号相同
      DatagramSocket ds = new DatagramSocket(9999);
    2. 创建数据包,用于存储收到数据。方便用数据包的方法解析这些数据
      byte[] buf = new byte[1024];
      DatagramPacket dp = new DatagramPacket(buf, buf.length);
    3. 通过UDP的Socket服务的receive方法将接收到的数据存储到数据包中
      ds.receive(dp);阻塞式
    4. 通过数据包对象的方法解析数据包的数据
      dp.getAddress().getHostAddress()获取发送方IP地址
      dp.getAddress().getHostName())获取发送方主机名
      new String(dp.getData(),0,dp.getLength())获取发送方数据
      dp.getPort()获取发送方端口号
    5. 关闭Socket服务
      ds.close();


UDP发送端

public static void main(String[] args) throws IOException {
    //1.创建UDP的Socket服务
    DatagramSocket ds = new DatagramSocket();
    //2.将要发送到数据封装到数据包中
    byte[] buf = "UDP传输演示,发送端数据".getBytes();
    DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 9999);
    //3.通过UDP的Socket服务的send()方法将数据包发送
    ds.send(dp);
    //4.关闭Socket服务
    ds.close();
}

UDP接收端

public static void main(String[] args) throws IOException {
    //1.建立Socket服务,因是接收数据,要绑定端口
    DatagramSocket ds = new DatagramSocket(9999);
    //2.创建数据包,用于存储收到数据。方便用数据包的方法解析这些数据
    byte[] buf = new byte[1024];
    DatagramPacket dp = new DatagramPacket(buf, buf.length);
    //3.通过UDP的Socket服务的receive方法将接收到的数据存储到数据包中
    ds.receive(dp);//阻塞式
    //4.通过数据包对象的方法解析数据包的数据
    System.out.println(dp.getAddress().getHostAddress());
    System.out.println(dp.getAddress().getHostName());
    System.out.println(new String(dp.getData(),0,dp.getLength()));
    System.out.println(dp.getPort());
    //5.关闭Socket服务
    ds.close();
}

TCP协议传输

TCP 对应Socket对象 两个: 客户端Socket 服务端ServerSocket

  • 发送端

    1. 创建TCP客户端socket服务。使用的是Socket对象
      • Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
      • Socket socket = new Socket("192.168.1.111", 9090);
      • Socket socket = new Socket();
        SocketAddress address = new InetSocketAddress("ip/主机名", 9090);
        socket.connect(address)
    2. 如果连接建立成功,说明数据传输通道建立
      该通道是socket流,是底层建立的,既有输入又有输出。从Socket获取输入/输出流流对象
      通过getOutputStream()getInputStream()来获取两个字节流
      获取Socket输出流对象, 通过该流把数据发送给服务器
      OutputStream out = ocket.getOutputStream();
    3. 使用输出流,将数据写出。
      out.write(String.getBytes());
    4. 关闭资源,断开连接
      socket.close();
  • 服务端

    1. 创建Socket服务,通过ServerScoket对象。服务器必须对外提供一个端口,否则客户端无法连接。
      ServerSocket serverSocket = new ServerSocket(9090);
    2. 获取连接过来的客户端对象。
      Socket socket = serverSocket.accept();
    3. 通过客户端对象获取Scoket流读取客户端发来的数据。
      InputStream in = socket.getInputStream();
      byte[] buf = new byte[1024];
      int len = in.read(buf);
      String str = new String(buf,0,len);
    4. 关闭资源。关客户端,关服务端。
      serverSocket.close();
      socket.close();


TCP客户端

public static void main(String[] args) throws IOException {
    // 建立TCP客户端与服务器的连接, 指定服务器的IP地址与程序对应的端口号
    Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
    //InetAddress address = InetAddress.getByName(IP/主机名) ;
    //Socket socket = new Socket(address, 9090);
    // 获取Socket输出流对象, 通过该流把数据发送给服务器
    OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream());
    //BufferedWriter bw = new BufferedWriter(socketOut);
    // 获取Socket输入流对象, 通过该流获得服务器发送给客户端的数据
    BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // 获取键盘输入流对象,读取数据
    BufferedReader keyboardReader = new BufferedReader(new InputStreamReader(System.in));
    String line = null;
    System.out.print("我说:");
    while ((line = keyboardReader.readLine()) != null) {
        socketOut.write(line + "\n");//阻塞方法,加入"\n"结束标记,告诉服务器我发送完毕,使用BufferedWriter,可以用bw.newLine()代替
        bw.write(line);
        // 刷新,见BufferWriter
        socketOut.flush();
        // 读取服务器端返回的数据
        line = socketReader.readLine();
        System.out.println("服务器:" + line);
        System.out.print("我说:");
    }
    socket.close();
}

TCP服务端

public static void main(String[] args) throws IOException {
    // 创建服务器端, 注册当前程序的端口号
    ServerSocket serverSocket = new ServerSocket(9090);
    // 接受客户端的连接,产⽣生⼀一个Socket
    Socket socket = serverSocket.accept();
    // 获取Socket的输⼊入流, 就是通过这个输入流获得客户端发送给服务器的数据
    BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // 获取Socket的输出流, 就是通过该输出流, 服务器把数据发送给客户端
    OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream());
    //BufferedWriter bw = new BufferedWriter(socketOut);
    // 获取键盘的输⼊入流,通过该输入流读取键盘上输入的数据
    BufferedReader keyboardReader = new BufferedReader(new InputStreamReader(System.in));
    // 不断读取客户端数据
    String line = null;
    while ((line = socketReader.readLine()) != null) {
        System.out.println("客户端:" + line);
        System.out.print("我说:");
        line = keyboardReader.readLine();
        socketOut.write(line + "\n");//阻塞方法,加入"\n"结束标记,告诉客户端我发送完毕,使用BufferedWriter,可以用bw.newLine()代替
        bw.write(line);
        socketOut.flush();//见BufferWriter
    }
    // 关闭
    serverSocket.close();
}

TCP多线程—多用户上传

客户端

public class TransClient {
	public static void main(String[] args) throws IOException {
	    // 建立TCP客户端与服务器的连接, 指定服务器的IP地址与程序对应的端口号
	    Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
	    //InetAddress address = InetAddress.getByName(IP/主机名) ;
	    //Socket socket = new Socket(address, 9090);
	    // 获取Socket输出流对象, 通过该流把数据发送给服务器
	    OutputStream outputStream = socket.getOutputStream();
	    InputStream is = new FileInputStream("D:/1.mp4");
	    byte[] bytes = new byte[256];
	    int len = is.read(bytes);//返回读取到的有效字节数
	    while(len != -1) {
	    	outputStream.write(bytes,0,len);
	    	len = is.read(bytes);
	    } 
	    socket.close();
	}
}

服务端

public class TransServer {
	public static void main(String[] args) throws IOException{
	    // 创建服务器端, 注册当前程序的端口号
	    ServerSocket serverSocket = new ServerSocket(9090);
	    while(true) {
	    	Socket socket = serverSocket.accept();
	    	new Thread(new Runnable() {
				
				@Override
				public void run() {
					OutputStream os = null;
					int connt = 0;
					try {
						// 获取Socket的输⼊入流, 就是通过这个输入流获得客户端发送给服务器的数据
						InputStream inputStream = socket.getInputStream();
						File f = new File("D:/","1.mp4");
						while(f.exists()) {
							f = new File("D:/","1("+(++connt)+").mp4");
						}
						os = new FileOutputStream(f);
						byte[] bytes = new byte[2048];
						int a = inputStream.read(bytes);
						while(a != -1)
						{
							os.write(bytes,0,a);
							a = inputStream.read(bytes);
						}
					} catch (IOException e) {
						e.printStackTrace();
					}finally {
						try {
							os.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
	    	// 接受客户端的连接,产生一个Socket
		    
	    }
	}
}

最常见的客户端:

浏览器 :IE

最常见的服务端:

服务器:Tomcat

为了了解其原理:

  • 自定义服务端

    public class MyTomcat {
    
      public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9090);
        Socket socket = serverSocket.accept();
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[2048];
        int len = in.read(buf);
        String text = new String(buf,0,len);
        System.out.println(text);
        StringBuffer reply = new StringBuffer();             // 必须添加的响应头
        reply.append("HTTP/1.1 200 OK\\nContent-type:text/html\n\n");// 必须添加的响应头
        InputStream is = new FileInputStream("D:/2.html");
        buf = new byte[2048];
          len = is.read(buf);//返回读取到的有效字节数
          while(len != -1) {
            reply.append(new String(buf,0,len));
            len = is.read(buf);
          }
        OutputStream outputStream = socket.getOutputStream();
        //此处不修改编码格式,需要html中指定
        outputStream.write(reply.toString().getBytes("GB2312"));
        socket.close();
        serverSocket.close();
    
      }
    }
    
  • 使用已有的客户端IE,了解一下客户端给服务端发了什么请求?

  • 客户端发送的请求是:

    //以下是请求行
    //格式为:请求方式 / 请求的资源路径 / http协议版本。
    GET / HTTP/1.1  
    //以下是请求消息头
    //格式为:属性名:属性值
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*  //支持解析的数据类型
    Accept-Language: zh-cn,zu;q=0.5   //支持的语言
    Accept-Encoding: gzip, deflate    //支持的压缩包
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)//用户信息
    Host: 127.0.0.1:9090      //要访问的主机
    //Host: www.huyouni.com:9090
    Connection: Keep-Alive(或者close)
    //空行
    //请求体(比如注册信息)。
    
  • 自定义客户端

    public class MyBrowser {
    
    public static void main(String[] args) throws UnknownHostException, IOException {
    	Socket s = new Socket("192.168.1.100",8080);
    	//模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
    	PrintWriter out = new PrintWriter(s.getOutputStream(),true);
    	out.println("GET /myweb/1.html HTTP/1.1");
    	out.println("Accept: */*");
    	out.println("Host: 192.168.1.100:8080");
    	out.println("Connection: close");
    	out.println();
    	out.println();
    	
    	InputStream in = s.getInputStream();
    	
    	byte[] buf = new byte[1024];
    	int len = in.read(buf);
    	
    	String str =new String(buf,0,len);
    	System.out.println(str);
    	
    	s.close();
    	
    	//http://192.168.1.100:8080/myweb/1.html
    }
    }
    
  • 服务端发回应答消息。

    //以下是应答行
    //http的协议版本  应答状态码   应答状态描述信息
    HTTP/1.1 200 OK 
    //以下是应答消息属性信息
    //属性名:属性值
    Server: Apache-Coyote/1.1
    ETag: W/"199-1323480176984"
    Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
    Content-Type: text/html
    Content-Length: 199
    Date: Fri, 11 May 2012 07:51:39 GMT
    Connection: close
    //空行
    //应答体。
    
    <html>
    <head>
    <title>这是我的网页</title>
    </head>
    <body>
    <h1>欢迎光临</h1>
    <font size='5' color="red">这是一个tomcat服务器中的资源。是一个html网页。</font>
    </body>
    </html>
    

URL统一资源定位器

  1. URL对象创建
    URL url = new URL("http://192.168.1.100:8080/myweb/1.html?name=list");

  2. 常用方法

    StringgetFile()获取此 URL的文件名
    StringgetHost()获取此 URL的主机名(如适用)
    StringgetPath()获取此 URL的路径部分
    intgetPort() 获取此URL的端口号
    StringgetProtocol()获取此 URL的协议名称
    StringgetQuery()获取此 URL的查询部分
    URLConnectionopenConnection()返回一个URLConnection实例,表示与URL引用的远程对象的URL
    InputStreamopenStream()打开与此 URL ,并返回一个 InputStream ,以便从该连接读取,相当于URLConnection conn = url.openConnection(); InputStream in = conn.getInputStream();的简写

在这里插入图片描述

URL统一资源定位器简易浏览器

String str_url = "http://192.168.1.100:8080/myweb/1.html";
URL url = new URL(str_url);
//获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
//InputStream in = url.openStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
in.close();

网络结构

  1. C/S client/server
    特点:
    该结构的软件,客户端和服务端都需要编写。
    可发成本较高,维护较为麻烦。
    好处:
    客户端在本地可以分担一部分运算。

  2. B/S browser/server
    特点:
    该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。
    开发成本相对低,维护更为简单。
    缺点: 所有运算都要在服务端完成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Socket网络编程是一种利用套接字(socket)实现客户端和服务端之间通信的编程技术。通过套接字,应用程序可以在网络上发送和接收数据,并与其他应用程序进行通信。Socket网络编程广泛应用于各种领域,如网络通信、网络游戏、聊天软件、远程监控和在线视频等。开发者需要熟悉相关的技术和编程知识,以实现高效和可靠的网络通信。在编程中,可以使用各种协议(如TCP/IP协议)来实现网络通信,通过socket对象进行数据交换和共享。通过创建套接字并打开网络文件,应用程序可以像操作文件一样对套接字进行读写操作,实现与其他应用程序之间的通信。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Pythonsocket网络编程](https://download.csdn.net/download/qq_41604569/87564062)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Socket网络编程](https://blog.csdn.net/weixin_61701822/article/details/131230710)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [【计算机网络】Socket编程](https://blog.csdn.net/m0_69442905/article/details/128701277)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值