Java Socket 学习笔记

Socket:英文中的意思是插座。

两个Java应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为一个Socket。

Java中所有关于网络编程的类都位于java.net包。

一、TCP的socket编程

TCP编程需要使用的两个类:Socket类与ServerSocket类,

分别用来实现双向连接的Client端和Server端。

说明:这里仅指TCP连接。因为UDP中没有Client和Server的概念。UDP只负责发送,不管是否发生成功。

 

建立连接时所需要的寻址信息为远程计算机的IP地址和端口号。

说明:

1.一个端口号只能被一个应用程序占用。

2.1024以下的端口号都由系统使用。普通应用程序不应该去占用。

3.比较有名的应用程序占用某个特定的端口号,一般也不该去占用。

    如HTTP端口,80端口。

        FTP,21端口。

        SMTP,25端口。

        接受邮件,110端口。

 

说明:TCP端口与UDP端口是两个不同的概念。TCP端口有65535个端口,UDP端口也有65536个端口。TCP的8888端口与UDP的8888端口是两个不同的概念。

 

ServerSocket的构造函数

ServerSocket()

ServerSocket(int port)

创建非绑定服务器套接字。

创建绑定到特定端口的服务器套接字。

ServerSocket常用API

Socket accept()  侦听并接受到此套接字的连接。该方法为阻塞方法,当没有接收到新的网络连接前是不会继续执行的。 

 

 

Socket的构造函数

Socket()

Socket(String host, int port)

若没建立连接会抛出异常。

 

 

 

 

例程

例:TCP的Server端

 

import java.net.*;
import java.io.*;

public class TCPServer {
    public static void main(String[] args) throws Exception {
	ServerSocket ss = new ServerSocket(6666); //建立监听
	while(true) {
		Socket s = ss.accept();//等待请求。若请求,则创建Socket,即建立连接。
System.out.println("a client connect!");
                //输入流
		DataInputStream dis = new DataInputStream(s.getInputStream());
		System.out.println(dis.readUTF());//从流中读出信息。
		dis.close();//关闭流。
		s.close();//关闭socket。
	}
    }
}

 

 

例:TCP的Client端

 

import java.net.*;
import java.io.*;

public class TCPClient {
    public static void main(String[] args) throws Exception {
	Socket s = new Socket("127.0.0.1", 6666); //建立Socket,寻址,申请连接。
	OutputStream os = s.getOutputStream(); //使用流做通信。输出流
	DataOutputStream dos = new DataOutputStream(os);
	Thread.sleep(30000);
	dos.writeUTF("hello server!");//以UTF-8的编码将数据写入流。
	dos.flush();    //压出流中所有信息。
	dos.close();    //关闭流。
	s.close();      //关闭socket。
    }
}

 

 

说明:

1. 网络应用程序的编程过程中,应该先启动Server再启动Client。而编程过程是Server与Client是同时编写的。

2. ServerSocket类的accept()方法是阻塞式的方法,即若没有接受到连接,则停止在该方法,不再继续执行。

3. 在例程中readUTF()方法也是阻塞式的方法。

4. Client端的端口是系统自动选择的,我们不需要去关注。

 

 

例程的缺点

1. 由于Server端的readUTF()方法是阻塞式的。Server需要等待Client发送数据才会继续执行,所以将会导致accept()方法无法执行。

2. 由于readUTF方法是阻塞方式的。所以如果read()和write()方法是在同一个处理过程中,必须是一段是先读后写,另一端是先写后读。若两个都是先后后写,则Server端和Client都不会继续执行。

 

 

 

 InetAddress:IP地址的超集。除了IP地址。还可以表示其他通信协议的地址。

 

 

 

 

二、UDP编程

UDP是不可靠的。UDP是基于数据报的形式发送数据。(TCP也本质也以数据报发送,但安全性强。)

对与UDP没有Server与Client的概念。

UDP编程中最重要的两个类:DatagramPacket与DatagramSocket

DatagramPacket类:

DatagramSocket类:

 

例程:

例:UDP的Server端

 

import java.net.*;
import java.io.*;

public class TestUDPServer
{
    public static void main(String args[]) throws Exception
    {
	byte buf[] = new byte[1024];
        //创建数据报。
	DatagramPacket dp = new DatagramPacket(buf, buf.length);  //该数据报与字节数组关联。
	DatagramSocket ds = new DatagramSocket(5678);    //占用5678端口。
	while(true)
	{
	    ds.receive(dp);//接受数据报。并把数据报传递至dp。即数据报中的数据存入buf。
	    ByteArrayInputStream bais = new ByteArrayInputStream(buf);  //从字节数组(源)接上读取流。
	    DataInputStream dis = new DataInputStream(bais);  //用Data流包装读取流。
	    System.out.println(dis.readLong());  //从Data流中读取数据。
        }
    }
}
 

 

 

例:TCP的Client端

 

import java.net.*;
import java.io.*;

public class TestUDPClient
{
    public static void main(String args[]) throws Exception
    {
        //首先将一个long数,装为字节数组。
	long n = 10000L;
	ByteArrayOutputStream baos = new ByteArrayOutputStream();  //创建写入内存的流(字节数组流)。该流用于向内存写数据。
	DataOutputStream dos = new DataOutputStream(baos);    //用数据流包装内存流。
	dos.writeLong(n);        //向数据流中写入long数。数据流负责把任何类型的数据写到内存流。通过内存流数据写到内存中。
	byte[] buf = baos.toByteArray(); //从内存流(字节数组流)中得到long数的byte数组。

        //创建数据报。
	DatagramPacket dp = new DatagramPacket(buf,
                                               buf.length,
                                               new InetSocketAddress("127.0.0.1", 5678)
                                               );
	DatagramSocket ds = new DatagramSocket(9999);  //占用9999端口。
	ds.send(dp);    //发送数据报。
	ds.close();     //关闭通信socket。
		
    }
}
 

 

 

说明:

DatagramSocket类的receive()方法阻塞式的方法。

InetAddress类继承了SocketAddress类。

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(java socket)