网络传输协议主要有TCP和UDP
UDP:
将数据及源和目的封装成数据包中,不需要建立连接
每个数据报的大小限制在64K
无连接,不可靠的协议
因不需要建立连接,速度快
TCP:
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
因必需建立连接,效率会低
实现两台机器的连接是通过Socket,UDP通过数据包DatagramPacket发送信息,
发送信息前都要建立DatagramSocket.
接受数据包要指明Socket端口,DatagramSocket ds = new DatagramSocket(10000),
比如上面10000端口接受数据。
发送数据包DatagramPacket里面要指明发送的IP和端口号,
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress
.getByName("localhost"), 10000);
比如上面指明发送buf字节数组中的内容到本地主机的10000端口
InetAddress类对象可以获得本地的IP和主机名字, 还可以通过getByName方法
根据名字获得主机地址。
InetAddress address = InetAddress.getLocalHost();
System.out.println(address);
System.out.println(address.getHostName());
System.out.println(address.getHostAddress());
InetAddress address1 = InetAddress.getByName("www.baidu.com");
System.out.println(address1);
上面程序打印:
myhome/169.254.126.92
myhome
169.254.126.92
www.baidu.com/119.75.218.45
下面是通过UDP发送数据的代码:
DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
String line = null;
while ((line = bufr.readLine()) != null)
{
if ("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress
.getByName("localhost"), 10000);
ds.send(dp);
}
ds.close();
下面是通过UDP接受数据的代码:
DatagramSocket ds = new DatagramSocket(10000);
while (true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "-----" + data);
}
通过dp.getAddress().getHostAddress()可以得到发送方的IP地址。
如果想实现两端的在线聊天可以让接受端和发送端都实现Runnable接口,
然后在每端起2个线程就可以了,UDP不分什么client端和server端,
下面是一端实现的代码:
接受线程
public class UdpClientReceive implements Runnable
{
private DatagramSocket ds;
public UdpClientReceive(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
while (true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
try
{
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "-----" + data);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
发送线程:
public class UdpClientSend implements Runnable
{
private DatagramSocket ds;
public UdpClientSend(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
String line = null;
try
{
while ((line = bufr.readLine()) != null)
{
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("localhost"), 10002);
ds.send(dp);
}
}
catch (Exception e)
{
e.printStackTrace();
}
ds.close();
}
}
起线程:
public class UdpMainServer
{
public static void main(String[] args) throws SocketException
{
DatagramSocket dssend = new DatagramSocket();
DatagramSocket dsreceive = new DatagramSocket(10002);
UdpServerSend send = new UdpServerSend(dssend);
UdpServerReceive receive = new UdpServerReceive(dsreceive);
new Thread(send).start();
new Thread(receive).start();
}
}
public class UdpMainClient
{
public static void main(String[] args) throws SocketException
{
DatagramSocket dssend = new DatagramSocket();
DatagramSocket dsreceive = new DatagramSocket(10000);
UdpClientSend send = new UdpClientSend(dssend);
UdpClientReceive receive = new UdpClientReceive(dsreceive);
new Thread(send).start();
new Thread(receive).start();
}
}
TCP连接中,有Server端,Server端会等待客户端的连接,
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();
就是等待10000端口客户端的连接,有客户端Socket s = new Socket(IP, 10000)就产生了一个连接,
IP为服务端IP的字符串表示形式。
s.getInputStream()和s.getOutputStream()可以拿到此端口的输入与输出。
下面代码实现连接,客户端发送字母,服务端以大写字母返回。
public class TransServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".....connected");
System.out.println("\n Server is ready ! \n ");
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String line = null;
while ((line = bufIn.readLine()) != null)
{
System.out.println(line);
out.println(line.toUpperCase());
}
s.close();
ss.close();
}
}
public class TransClient
{
public static void main(String[] args) throws IOException
{
Socket s = new Socket("127.0.0.1", 10000);
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String line = null;
while ((line = bufr.readLine()) != null)
{
if ("over".equals(line))
break;
out.println(line);
String str = bufIn.readLine();
System.out.println("server:" + str);
}
}
}
TCP要实现客户端与服务端的在线聊天,也是分别实现发送和接受线程,
然后客户端与服务端都起2个线程就可以了,线程都接受socket的引用。
下面是客户端代码:
接受数据
public class ClientInputThread extends Thread
{
private Socket socket;
public ClientInputThread(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try
{
InputStream is = socket.getInputStream();
while(true)
{
byte[] buffer = new byte[1024];
int length = is.read(buffer);
String str = new String(buffer, 0, length);
System.out.println(str);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
发送键盘录入数据
public class ClientOutputThread extends Thread
{
private Socket socket;
public ClientOutputThread(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try
{
OutputStream os = socket.getOutputStream();
while (true)
{
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
String line = reader.readLine();
os.write(line.getBytes());
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
起线程:
public class MainClient
{
public static void main(String[] args) throws Exception, IOException
{
Socket socket = new Socket("127.0.0.1", 4000);
new ClientInputThread(socket).start();
new ClientOutputThread(socket).start();
}
}
当我们在浏览器里输入http://127.0.0.1:8080/hello/Login.jsp
表示访问本地主机8080端口下的hello资源下的Login.jsp文件,然后
服务器就会把Login.jsp的信息返回给我们。
当我们在浏览器输入http://www.baidu.com其实是访问百度主机下的
80端口的首页面index.html,然后浏览器会把百度首页面的信息返回给我们,
我们可以通过程序模拟浏览器发出请求的过程:
如下面的程序请求我本地主机的8080端口Tomcat服务器下hello资源下的jsp页面,
返回的信息打印到控制台:
Socket s = new Socket("127.0.0.1", 8080);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("GET /hello/first.jsp HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 127.0.0.1:8080");
out.println("Connection: Keep-Alive");
out.println();
out.println();
BufferedReader bufr = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String line = null;
while ((line = bufr.readLine()) != null)
{
System.out.println(line);
}
s.close();
打印输出:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=FC3BF3D5CF07968FE1EA7A4B60991142; Path=/hello
Content-Type: text/html;charset=UTF-8
Content-Length: 1108
Date: Sun, 06 Nov 2011 07:39:54 GMT
页面内容……………………………………
表示请求采用HTTP1.1协议,请求成功等信息,当我们用浏览器请求的时候,
只返回请求体,请求头的信息给拆包了。
我们还可以把IP信息封装成URL对象,通过API得到具体信息。
URL url = new URL("http://127.0.0.1:8080/hello/first.jsp?name=haha&age=25");
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort());
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getQuery());
上面程序打印:
http
127.0.0.1
8080
/hello/first.jsp
/hello/first.jsp?name=haha&age=25
name=haha&age=25
URL中的openConnection()方法可以返回一个URLConnection对象,
该对象封装了创建连接的过程,拿到远程对象的实际连接,
URL url = new URL(urlPath);
URLConnection con = url.openConnection();
InputStream in = con.getInputStream();
byte[] buf = new byte[1024];
String str = null;
int len;
while ((len = in.read(buf)) != -1)
{
str = new String(buf, 0, len);
System.out.println(str);
}
假如上面的urlPath为http://www.baidu.com,则会在控制台打印出
百度首页面的信息。
网络编程主要是通过TCP和UDP协议实现多点之间的通信,与多线程、IO技术
结合应用的比较多,关于这部分的学习就总结到这了,谢谢。