UDP:
a) 将数据及源和目的封装成数据包中,不需要建立连接
b) 每个数据报的大小限制在64K内
c) 因无连接,是不可靠协议
d) 不需要建立连接,速度快
TCP:
a) 建立连接,形成传输数据的通道
b) 在连接中进行大数据传输
c) 通过三次握手完成连接,是可靠协议
应用:
1,TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
2,UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
基于Socket的java网络编程
a) 就是为网络服务提供的一种机制
b) 通信的两端都有Socket
c) 网络通信其实就是socket间的通信
d) 数据在2个Socket间通过IO传输
1,什么是Socket
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
2,Socket通讯的过程
Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1) 创建Socket;
(2) 打开连接到Socket的输入/出流;
(3) 按照一定的协议对Socket进行读/写操作;
(4) 关闭Socket.(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。)
3,创建Socket
创建Socket
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr,int localPort)
Socket(InetAddress address, int port, InetAddresslocalAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddressbindAddr)
其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和 bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可 以用来创建Socket。count则表示服务端所能支持的最大连接数。
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才 能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。端口范围:0-65535,其中0~1024系统使用或保留端口
在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。
4,支持多客户的client/server程序
前面的Client/Server程序只能实现Server和一个客户的对话。在实际应用 中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,提供相应的服务。为了实现在服务器方给多个客户提供服务的功能,需要对上 面的程序进行改造,利用多线程实现多客户机制。服务器总是在指定的端口上监听是否有客户请求,一旦监听到客户请求,服务器就会启动一个专门的服务线程来响 应该客户的请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。
5,简单的Client/Server程序
获得指定url的ip地址及名字
package com.wj.ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 得到ip地址
* @author wJing
* time:2014/2/9
*/
public class IPDemo1 {
/**
*
* @param args
* @throws Exception
*/
public staticvoid main(String[] args) throws Exception {
InetAddress i= InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println(i.getHostName());
System.out.println(i.getHostAddress());
InetAddressia = InetAddress.getByName("127.0.0.1");
System.out.println("address:"+ia.getHostAddress());
System.out.println("ip:"+ ia.getHostName());
}
}
简单的Client(发送文本):
package com.wj.client;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
*
* @author wJing
* time:2014-2-915:09:54
* 把客户端的一个文件传递到服务端,模拟
*/
public class TextClient {
public staticvoid main(String[] args) throws Exception, IOException {
Socket s =new Socket("localhost", 9999);
BufferedReaderbuf = new BufferedReader(new FileReader("d:\\abcde.txt"));
PrintWriterwriter = new PrintWriter(s.getOutputStream(),true);
/*
/
//时间戳,确定文件的结束标记
DataOutputStreamdos = new DataOutputStream(s.getOutputStream());
long time =System.currentTimeMillis();
dos.writeLong(time);
*/
String line =null;
while((line =buf.readLine()) != null) {
writer.println(line);
}
//关闭客户端输出流
s.shutdownOutput();
// writer.println(time);//文件读完以后再发一次时间戳
///
BufferedReaderin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str =in.readLine();
System.out.println(str);
buf.close();
s.close();
}
}
简单的Server(接收文本):
package com.wj.server;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TextServer {
public staticvoid main(String[] args) throws Exception {
ServerSocketss = new ServerSocket(9999);
Socket s =ss.accept();
BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriterin = new PrintWriter(new FileWriter("e://copy.txt"),true);
/**
*
///
DataInputStreamdis = new DataInputStream(s.getInputStream());
long time =dis.readLong();
///
/**
* 方式1:发送一个标记给服务器
* 方式2:使用时间戳当作一个标记
* 方式3:使用socket的shutdowninput、shutdownoutput
*/
String line =null;
while((line =bufIn.readLine()) != null) {
// if(line.equals(time)){
// break;
// }
in.println(line);
}
PrintWriterout = new PrintWriter(s.getOutputStream(), true);
out.println("上传成功");
in.close();
s.close();
ss.close();
}
}
简单的Client(发送图片):
package com.wj.client;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*
* @author wJing
* time:2014-2-916:38:57
* 上次图片
*/
public class ImageClient {
public staticvoid main(String[] args) throws Exception, IOException {
Socket s =new Socket("localhost", 1520);
FileInputStreamfis = new FileInputStream("d:\\1.jpg");
OutputStreamout = s.getOutputStream();
byte[] buf =new byte[1024];
int len = 0;
while((len =fis.read(buf)) != -1) {
out.write(buf,0, len);
}
//告诉服务器数据已写完
s.shutdownOutput();
InputStreamin = s.getInputStream();
byte[] bufIn= new byte[1024];
int num =in.read(bufIn);
System.out.println(newString(bufIn, 0, num));
fis.close();
s.close();
}
}
简单的Server(接收图片)
package com.wj.server;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
class picThread implements Runnable {
private Socket s;
publicpicThread(Socket s) {
this.s = s;
}
@Override
public void run(){
int count =1;
String ip =s.getInetAddress().getAddress().toString();
System.out.println(ip+ ".....connected");
try {
InputStreamin = s.getInputStream();
File file =new File(ip+count + ".jpg");
while(file.exists()){
file = newFile(ip + "(" + count++ + ").jpg");
}
FileOutputStreamfos = new FileOutputStream(file);
byte[] buf =new byte[1024];
int len = 0;
while((len =in.read(buf)) != -1) {
fos.write(buf,0, len);
}
OutputStreamout = s.getOutputStream();
out.write("上次成功".getBytes());
fos.close();
s.close();
}catch(Exception e) {
throw newRuntimeException(ip + "上传失败");
}
}
}
public class ImageServer {
public staticvoid main(String[] args) throws Exception {
// UploadPic();
//使用多线程处理多个客户端的访问
ServerSocketss = new ServerSocket(1520);
while(true) {
Socket s =ss.accept();
newThread(new picThread(s)).start();
}
}
//先线程的图片上传,一个客户端连上以后只有等为他服务完成以后才能为下一个人服务
private staticvoid UploadPic() throws IOException, FileNotFoundException {
ServerSocketss = new ServerSocket(1520);
// while(true) {
Socket s =ss.accept();
InputStreamin = s.getInputStream();
FileOutputStreamfos = new FileOutputStream("e:\\server.jpg");
byte[] buf =new byte[1024];
int len = 0;
while((len =in.read(buf)) != -1) {
fos.write(buf,0, len);
}
OutputStreamout = s.getOutputStream();
out.write("上次成功".getBytes());
fos.close();
s.close();
// }
ss.close();
}
}
一个基于UDP的简单聊天程序:
package com.wj.udp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
*
* @author wJing
*编写一个聊天程序
*time:2014-2-9 11:33:20
*/
class Send implements Runnable {
privateDatagramSocket ds;
publicSend(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run(){
try {
BufferedReaderin = new BufferedReader(new InputStreamReader(System.in));
Stringline = null;
while((line= in.readLine()) != null) {
if("886".equals(line)){
break;
}
byte[] buf = line.getBytes();
DatagramPacketdp = new DatagramPacket(buf, buf.length,InetAddress.getByName("localhost"), 10002);
ds.send(dp);
}
} catch(Exception e) {
throw newRuntimeException("发送端失败");
}
}
}
class Receive implements Runnable {
private DatagramSocketds;
publicReceive(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run(){
try {
while(true){
byte[]buf = new byte[1024 * 64];
DatagramPacketdp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
Stringip = dp.getAddress().getHostAddress();
Stringdata = new String(dp.getData(), 0, dp.getLength());
System.out.println("ip->"+ ip + ":" + data);
}
} catch(Exception e) {
throw newRuntimeException("接收失败");
}
}
}
public class ChatDemo {
public staticvoid main(String[] args) throws Exception {
DatagramSocketsendSocket = new DatagramSocket();
DatagramSocketreceiveSocket = new DatagramSocket(10002);
newThread(new Send(sendSocket)).run();
newThread(new Receive(receiveSocket)).run();
}
}