什么是计算机网络
通俗讲:两台电脑连在一起就组成了一个计算机网络。我们通过光钎连接到电信的网关,中国电信通过海底光缆和美国电信网关连接,你就是和全世界的在线用户连着。
网络编程就是在两个或连个以上的设备之间传输数据
什么是网络通信协议
网络通信协议就像我们的中文一样,她就是我们之间的共同语言,他规定了我们之间怎么说话,我先说什么你再说什么,你怎么说,而我怎么听。而网络通信得先规定一些俗称的网络通信协议,先说好,两台计算机之间什么收发信息,信息格式是什么,信息怎么发,怎么接受,而万一出错怎么办怎么处理。
UDP和TCP
TCP和TCP都是传输层协议
网络应用中基本上都是TCP和UDP,TCP是面向连接的通信协议,UDP是无连接的通信协议。
TCP协议特点
传输控制协议,提供的是面向连接,可靠的字节流服务。
当客户和服务器彼此交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。
TCP提供超时重发,丢弃数据,检验数据,流量控制等功能,保证数据能从一端到另一端。
UDP协议特点
UDP不提供可靠性,它只能把应用程序传给IP层的数据包发送出去,但是并不能保证他们能到达目的地。
UDP传输数据时是有大小限制的,每一个被传输的数据包必须限定在64kB之内。
由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
应用
TCP通信在网络上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的宽带,因此TCP传输的效率不如UDP高。
UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中Client/sever 应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
127.0.0.1是回路地址,用于测试,相当于localhost本机地址,没有网卡,不设DNS都可以访问.
端口地址在0~65535之间,其中0~1023之间的端口是用于一些知名的网络服务和应用,用户的普通网络应用程序应该使用1024以上的端口.
Socket连接套接字,java分别为TCP和UDP提供了相应的类,TCP是java.net.ServerSocket(用于服务器端)和java.net.Socket(用于客户端);UDP是java.net.DatagramSocket.
Java编写UDP网络程序
相关类介绍:
DatagramSocket
有如下构造方法
1.DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
2.DatagramSocket(int port);创建数据报套接字并将其绑定到本地主机上的指定端口。
3.DatagramSocket(int port,InetAddressladdr):创建数据报套接字,并将其绑定到指定的本地地址。即指定网卡发送和接受数据。
如果在创建DatagramSocket对象是,没有指定网卡的IP地址,在发送数据时,底层驱动程序会自动选择一块网卡去发送,在接收数据时,会接收所有的网卡收到的与端口一致的数据。
发送信息时,可以不指定端口号,接收信息时,要指定端口号,因为接收指定的数据。
发送数据使用DatagramSocket.send(DatagramPacketp)方法;
接收数据使用DatagramSocket.receive( DatagramPacketp)方法;DatagramPacket
Datagrampacket类有如下构造方法:
1. DatagramPacket(byte[]buf,int length);//构造DatagramPacket,用来接收长度为length的数据包。
2. DatagramPacket(byte[] buf,intlength,InetAddress address,int port);构造数据报,将长度为length的包发送到指定主机上的指定端口。
接收数据时,第一种构造方法,发送数据时使用第二种构造方法
InetAddress
Java中对Ip地址进行包装的类,。DatagramPacket.getAddress()可以获取发送或接收方的IP地址,DatagramPacket.getPort()可以获取发送或接受方的端口
UDP程序例子
发送数据代码:
接收数据代码
Java编写TCP网络程序
ServerSocket
编写TCP网络服务程序,首先要用到java.net.ServerSocket类型泳衣创建服务器Socket它的常用构造方法有:
1. ServerSocket(int port):创建绑定到指定端口的服务器套接字。
2. ServerSocket(int port, intbacklog):利用指定的backlog(服务器忙时保持连接请求的等待客户数量),创建服务器套接字并将其绑定到指定的本地端口号
3. ServerSocket(int port,intbacklog,inetAddress bindaddr):使用指定的端口、侦听backlog 和要绑定到的本地IP地址创建服务器。
Socket
客户端要与服务器建立连接,必须先创建一个Socket对象,它的常用构造方法有:
1. Socket(Stringhost,int port):创建一个流套接字并将其连接到指定主机上的指定端口号。
2. Socket(InetAddress address,intport):创建一个流套接字并将其连接到指定IP地址的指定端口号。
3. Socket(InetAddress address,intport,Inetaddress localAddr,int localPort):创建一个套接字并将其连接到指定远程端口上的指定远程地址。
4. Socket(Stringhost,int prot,InetAddress localAddr,int localPort):创建一个套接字并将其连接到指定远程主机上的指定远程端口。
对于通常情况的应用,使用第一个构造方法来创建Socket对象,并与服务器建立连接,是非常简单和方便的
服务器程序调用ServerSocket.accept方法等待客户端的连接请求,一旦accept接收了客户端连接请求,该方法返回一个与该客户建立了专线连接的Socket对象,不用程序去创建这个Socket对象,建立了连接的两个Socket是IO流的方式进行数据交换的,java提供了Socket.getInputStream返回Socket的输入流对象,socket.getOutputStream返回Socket 的输出流对象。
大多数情况下,服务器都要服务多个客户端,但一次accept方法只接受一个连接,因此要把accept方法放在一个循环语句中,这样就可以接收多个连接,每个连接的数据交换代码也放在一个循环中,这样才能保证两者可以不听的交换数据。
每个连接的数据交换代码必须放在独立的线程中运行,否则这段代码运行期间,就没法执行其他的程序代码,accept方法也得不到调用,进的连接无法进入。
例子
服务器代码:import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
//建立服务器
ServerSocket ss=new ServerSocket(7000);
while(true){
//与客户端建立连接
Socket s=ss.accept();
//创建匿名类对象,并启动此对象的一个线程
new Thread(new Servicer(s)).start();
}
}
};
//建立Servicer类
class Servicer implements Runnable{
Socket s;//得到Socket类的引用s
//创建构造方法
public Servicer(Socket s) {
this.s=s;
}
//重写run()方法启动线程
@Override
public void run() {
try {
//得到输入输出流
InputStream ips=s.getInputStream();
OutputStream ops=s.getOutputStream();
//将字节流转换成字符流并使用BuffeedReader读取,碰到换行才结束
BufferedReader br=new BufferedReader(new InputStreamReader(ips));
//读不同的数据类型
DataOutputStream dos=new DataOutputStream(ops);
while(true){
//按行读取客户端输入的内容
String strWord=br.readLine();
//判断内容是否为quit,如果是结束循环
if(strWord.equalsIgnoreCase("quit")){
break;
}
//将得到的字符串转换为StringBuffer并且反转,最后变为String存入strEcho中
String strEcho=new StringBuffer(strWord).reverse().toString();
//将内容写给客户端
dos.writeBytes(strWord+"------>"+strEcho+System.getProperty("line.separator"));
}
br.close();
dos.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static void main(String args[]) throws Exception {
Socket s=new Socket(InetAddress.getLocalHost(), 7000);
//输入输出流接收或发送数据
InputStream ips = s.getInputStream();
OutputStream ops = s.getOutputStream();
//字符流按行读取
BufferedReader brKey = new BufferedReader(new InputStreamReader(
System.in));
//得到输出流
DataOutputStream dos = new DataOutputStream(ops);
//接收服务器端的数据
BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
while(true){
//按行读取数据
String strWord = brKey.readLine();
dos.writeBytes(strWord + System.getProperty("line.separator"));//写数据加入换行符发送到服务器
//如果输入输入为quit
if("quit".equalsIgnoreCase(strWord)){
break;
}else{
System.out.println(brNet.readLine()); //将服务器数据打印输出
}
}
dos.close();
brNet.close();
brKey.close();
s.close();
}
}