Java的Socket网络编程基础知识入门教程

一、TCP/IP简介

TCP/IP协议族是互联网使用的协议,也可以用在独立的专用网络中。
TCP/IP协议族包括了IP协议、TCP协议和UDP协议。

IP协议使用IP地址来分发报文,但它是尽力而为的服务,报文可能丢失、乱序或者
重复发送。TCP和UDP协议在IP协议基础上增加了端口号,从而在两台主机的应用
程序间建立起透明的连接。

不同的是,TCP协议会对IP层的错误进行修复,它通过握手消息在主机间建立连接,
之后通过在消息中加入序列号来恢复消息中的错误。而UDP只是简单地扩展了IP协议,
使它能够在应用程序之间工作,而不是主机之间。

关于IP地址,一台主机可以有多个网络接口,而一个接口又可以有多个地址。
有些IP地址是有特殊用途的:

A.回环地址:127.0.0.1,总是被分配给一个回环接口,主要用于测试。

B.私有地址:以10、192.168、172.(16-31)开头,用于私有网络。NAT设备转发报文
时,将一个接口中报文的私有地址端口对映射成另一个接口中的公有地址端口对。这
就使一小组主机能够共享一个IP地址对。

C.多播地址:第一个数字在224~239之间。

二、Socket基础

1.地址的获得

public static void main(String[] args) { 

  try {
    Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
    while (interfaces.hasMoreElements()) {
      NetworkInterface iface = interfaces.nextElement();
      System.out.println("Interface: " + iface.getName()); 

      Enumeration<InetAddress> addrList = iface.getInetAddresses();
      if (!addrList.hasMoreElements())
        System.out.println("No address"); 

      while (addrList.hasMoreElements()) {
        InetAddress address = addrList.nextElement();
        System.out.println("Address: " + address.getHostAddress());
      }
    } 

  } catch (SocketException e) {
    e.printStackTrace();
  } 

}

2.TCP实例程序

要注意一点,虽然在Client端只用了一个write()方法发送字符串,服务器端也可能从
多个块中接受该信息。即使回馈字符串在服务器返回时存于一个块中,也可能被TCP
协议分割成多个部分。

TCPEchoClientTest.java

public static void main(String[] args) throws IOException { 

  String server = args[0];
  byte[] data = args[1].getBytes();
  int port = 7; 

  Socket socket = new Socket(server, port);
  System.out.println("Connected to server..."); 

  InputStream in = socket.getInputStream();
  OutputStream out = socket.getOutputStream(); 

  out.write(data); 

  int totalBytesRcvd = 0;
  int bytesRcvd;
  while (totalBytesRcvd < data.length) {
    if ((bytesRcvd = in.read(data, totalBytesRcvd,
        data.length - totalBytesRcvd)) == -1)
      throw new SocketException("Connection closed");
    totalBytesRcvd += bytesRcvd;
  } 

  System.out.println("Received: " + new String(data)); 

  socket.close();
}

TCPEchoServerTest.java

private static final int BUFSIZE = 32; 

public static void main(String[] args) throws IOException { 

  ServerSocket serverSocket = new ServerSocket(7); 

  int recvMsgSize;
  byte[] receiveBuf = new byte[BUFSIZE];
  while (true) {
    Socket socket = serverSocket.accept();
    System.out.println("Handling client " +
        " from remote " + socket.getRemoteSocketAddress() +
        " at local " + socket.getLocalSocketAddress()); 

    InputStream in = socket.getInputStream();
    OutputStream out = socket.getOutputStream(); 

    while ((recvMsgSize = in.read(receiveBuf)) != -1) {
      out.write(receiveBuf, 0, recvMsgSize);
    }
    socket.close();
  } 

}

注意new Socket时指定的是远端服务器监听的端口号而没有指定本地端口,因此将
采用默认地址和可用的端口号。在我的机器上Client端口是4593,连接到服务器的
端口7。

3.UDP实例程序

为什么使用UDP协议?如果应用程序只交换少量的数据,TCP连接的建立阶段就至少
要传输其两倍的信息量(还有两倍的往返时间)。

UDPEchoClientTest.java

public static void main(String[] args) throws IOException { 

  InetAddress serverAddress = InetAddress.getByName(args[0]);
  byte[] bytesToSend = args[1].getBytes(); 

  DatagramSocket socket = new DatagramSocket();
  socket.setSoTimeout(3000); 

  DatagramPacket sendPacket = new DatagramPacket(
    bytesToSend, bytesToSend.length, serverAddress, 7); 

  DatagramPacket receivePacket = new DatagramPacket(
    new byte[bytesToSend.length], bytesToSend.length); 

  // Packets may be lost, so we have to keep trying
  int tries = 0;
  boolean receivedResponse = false;
  do {
    socket.send(sendPacket);
    try {
      socket.receive(receivePacket);
      if (!receivePacket.getAddress().equals(serverAddress))
        throw new IOException("Receive from unknown source");
      receivedResponse = true;
    }
    catch (IOException e) {
      tries++;
      System.out.println("Timeout, try again");
    }
  } while (!receivedResponse && tries < 5); 

  if (receivedResponse)
    System.out.println("Received: " + new String(receivePacket.getData()));
  else
    System.out.println("No response"); 

  socket.close();
}

UDPEchoServerTest.java

private static final int ECHOMAX = 255;  

public static void main(String[] args) throws IOException { 

  DatagramSocket socket = new DatagramSocket(7);
  DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX); 

  while (true) {
    socket.receive(packet);
    System.out.println("Handling client at " + packet.getAddress()); 

    socket.send(packet);
    packet.setLength(ECHOMAX);
  } 

}

通过这个例子与之前TCP的实例进行比较,有如下区别:

A.DatagramSocket在创建时不需要指定目的地址,因为UDP不需要建立连接,每个
数据报文都可以发送或接收于不同的目的地址。

B.如果像TCP一样在read()上阻塞等待,将可能永远阻塞在那里,因为UDP协议只是
简单地扩展了IP协议,UDP报文可能丢失掉。所以一定要设置阻塞等待的超时时间。

C.UDP协议保留了消息的边界信息,每次receive()调用最多只能接收一次send()方法
调用所发送的数据。

D.一个UDP报文DatagramPacket能传输的最大数据是65507字节,超出部分的字节将
自动被丢弃,而且对接收程序也没有任何的提示。因此缓存数组可以设置成65000字节
左右是安全的。

E.如果反复使用同一个DatagramPacket实例调用receive()方法,每次调用前都必须显式
地将消息的内部长度重置为缓存区的实际长度。

时间: 2016-01-18

Java套接字(Socket)网络编程入门

网络应用模式主要有: 主机/终端模式:集中计算,集中管理: 客户机/服务器(Client/Server,简称C/S)模式:分布计算,分布管理: 浏览器/服务器模式:利用Internet跨平台. www(万维网)就是建立在客户机/服务器模式上,以HTML语言和HTTP协议为基础,能够提供各种Internet服务的信息浏览系统.网络信息放在主机的不同位置,www服务器利用超文本链路链接各项信息.www客户机(浏览器Brower)负责与服务器建立联系,向服务器发送请求,处理HTML超媒体,提供图形用户

Java网络编程基础篇之单向通信 原创

在网络编程中如果只要求客户机向服务器发送消息,不要求服务器向客户机发送消息,称为单线通信.客户机套接字和服务器套接字链接成功后,可估计通过输出流发送数据,服务器则通过输入流接受数据,下面是简单的单向通信的例子. 实例1:本实例是一个TCP服务器端程序,在 getserver() 方法中建立服务器套接字,调用getClienMessage()方法获取客户端信息.代码如下: import java.io.BufferedReader; import java.io.IOException; impo

Java网络编程基础教程之Socket入门实例

当我们想要在Java中使用TCP/IP通过网络连接到服务器时,就需要创建java.net.Socket对象并连接到服务器.假如希望使用Java NIO,也可以创建Java NIO中的SocketChannel对象. 创建Socket 下面的示例代码是连接到IP地址为78.64.84.171服务器上的80端口,这台服务器就是我们的Web服务器(www.jb51.net),而80端口就是Web服务端口. 复制代码 代码如下: Socket socket = new Socket("78.46.84.

java网络编程基础知识介绍

网络基础知识 1.OSI分层模型和TCP/IP分层模型的对应关系 这里对于7层模型不展开来讲,只选择跟这次系列主题相关的知识点介绍. 2.七层模型与协议的对应关系 网络层 ------------ IP(网络之间的互联协议) 传输层 ------------ TCP(传输控制协议).UDP(用户数据报协议) 应用层 ------------ Telnet(Internet远程登录服务的标准协议和主要方式).FTP(文本传输协议).HTTP(超文本传送协议) 3.IP地址和端口号 1.ip地址用于

Java网络编程之简单的服务端客户端应用实例

本文实例讲述了Java网络编程之简单的服务端客户端应用.分享给大家供大家参考.具体如下: 在Java中,我们使用java.net.Socket及其相关类来完成有关网络的相关功能.Socket类非常简单易用,因为Java技术隐藏了建立网络连接和通过连接发送数据的复杂过程.下面所说的内容只适用于TCP协议. 一.连接到服务器 我们可以使用Socket类的构造函数来打开一个套接字,如 Socket sk = new Socket("210.0.235.14",13); 其中,210.0.23

简单讲解Java的Socket网络编程的多播与广播实现

在Java中,我们可以有很多种方法来发送和接收数据.有的方法比较靠近底层,有些问题就需要程序员自己去解决,而有些方法抽象层次比较高,很方便地就可以拿来使用.这些处理数据的方法根据抽象层次由低到高分别有: 1.手动编码:使用位运算逐个自己编码和解析. 2.利用流来自动编码:组合使用OutputStream和ByteArrayOutputStream. 3.序列化:将数据放入一个数据对象中,直接将这个对象序列化后发送. 使用起来很方便,但要注意效率的损失,以及接收方也要使用Java. 4.RMI:将

简单介绍Java网络编程中的HTTP请求

HTTP请求的细节--请求行   请求行中的GET称之为请求方式,请求方式有:POST.GET.HEAD.OPTIONS.DELETE.TRACE.PUT,常用的有: GET. POST 用户如果没有设置,默认情况下浏览器向服务器发送的都是get请求,例如在浏览器直接输地址访问,点超链接访问等都是get,用户如想把请求方式改为post,可通过更改表单的提交方式实现. 不管POST或GET,都用于向服务器请求某个WEB资源,这两种方式的区别主要表现在数据传递上:如果请求方式为GET方式,则可以在请

Java 网络编程socket编程等详解

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net包中J2SE的API包含有类和接口,它们提供低层次的通信细节.你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节. java.net包中提供了两种常见的网络协议的支持: TCP: TCP是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信.通常用于互联网协议,被称TCP / IP. UDP:UDP是用户数据报协议的缩写,一个无连接的协议.提供了应用程序之间要发送的数据的数据包. 本教程

IOS开发网络篇—Socket编程详解

一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象: 传输层.会话层.表示层和应用层则被称作主机层,是用户所面向和关心的内容. http协议对应于应用层 tcp协议对应于传输层 ip协议对应于网络层 三者本质上没有可比性.  何况HTTP协议是基于TCP连接的. TCP/IP是传输层协议,主要解决数据如何在网络中传输:而HTTP是应用

Java并发编程Semaphore计数信号量详解

Semaphore 是一个计数信号量,它的本质是一个共享锁.信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量). 简单示例: package me.socketthread; import java.util.concurrent.ExecutorService;

Java并发编程总结——慎用CAS详解

一.CAS和synchronized适用场景 1.对于资源竞争较少的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源:而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能. 2.对于资源竞争严重的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized.以java.util.concurrent.atomic包中AtomicInteger类为例,其getAn

Java编程swing组件JLabel详解以及使用示例

JLabel 对象可以显示文本.图像或同时显示二者.可以通过设置垂直和水平对齐方式,指定标签显示区中标签内容在何处对齐.默认情况下,标签在其显示区内垂直居中对齐.默认情况下,只显示文本的标签是开始边对齐:而只显示图像的标签则水平居中对齐. 还可以指定文本相对于图像的位置.默认情况下,文本位于图像的结尾边上,文本和图像都垂直对齐. 构造方法介绍: JLabel() 创建无图像并且其标题为空字符串的 JLabel. JLabel(Icon image) 创建具有指定图像的 JLabel 实例. JL

Java编程复用类代码详解

本文研究的主要是Java编程中的复用类,那么到底复用类是什么东西,又有什么用法,下面具体介绍. 看了老罗罗升阳的专访,情不自禁地佩服,很年轻,我之前以为和罗永浩一个级别的年龄,也是见过的不是初高中编程的一位大牛之一,专访之后,发现老罗也是一步一个脚印的人.别说什么难做,做不了,你根本就没去尝试,也没有去坚持. If you can't fly then run,if you can't run then walk, if you can't walk then crawl,but whateve

Java并发编程预防死锁过程详解

这篇文章主要介绍了Java并发编程预防死锁过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在java并发编程领域已经有技术大咖总结出了发生死锁的条件,只有四个条件都发生时才会出现死锁: 1.互斥,共享资源X和Y只能被一个线程占用 2.占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X 3.不可抢占,其他线程不能强行抢占线程T1占有的资源 4.循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有

Java中CountDownLatch进行多线程同步详解及实例代码

Java中CountDownLatch进行多线程同步详解 CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantLock.ReadWriteLock锁实现同步. 3.信号量Semaphore实现同步. 其中,synchronized关键字和Lock锁解决的是多个线程对同一资源的并发访问问题.信号量Semaphore解决的是多副本资源的共享访问问题. 今天

Java探索之Feign入门使用详解

一,简介 Feign使得 Java HTTP 客户端编写更方便.Feign 灵感来源于Retrofit.JAXRS-2.0和WebSocket.Feign最初是为了降低统一绑定Denominator到HTTP API的复杂度,不区分是否支持Restful.Feign旨在通过最少的资源和代码来实现和HTTP API的连接.通过可定制的解码器和错误处理,可以编写任意的HTTP API. Maven依赖: <!-- https://mvnrepository.com/artifact/com.netf

Java源码解析之GenericDeclaration详解

学习别人实现某个功能的设计思路,来提高自己的编程水平.话不多说,下面进入正题. GenericDeclaration 可以声明类型变量的实体的公共接口,也就是说,只有实现了该接口才能在对应的实体上声明(定义)类型变量,这些实体目前只有三个:Class(类).Construstor(构造器).Method(方法)(详见:Java源码解析之TypeVariable详解 源码 public interface GenericDeclaration { //获得声明列表上的类型变量数组 public T

基于Java中的数值和集合详解

数组array和集合的区别: (1) 数值是大小固定的,同一数组只能存放一样的数据. (2) java集合可以存放不固定的一组数据 (3) 若程序事不知道究竟需要多少对象,需要在空间不足时自动扩增容量,则需要使用容器类库,array不适用 数组转换为集合: Arrays.asList(数组) 示例: int[] arr = {1,3,4,6,6}; Arrays.asList(arr); for(int i=0;i<arr.length;i++){ System.out.println(arr[