基础知识
1. TCP协议
是一种面向连接的、可靠的、基于字节流的运输层(Transport layer)通信协议。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层内另一个重要的传输协议。
TCP所提供服务的主要特点:面向连接的传输;端到端的通信;高可靠性,确保传输数据的正确性,不出现丢失或乱序;全双工方式传输;采用字节流方式,即以字节为单位传输字节序列;紧急数据传送功能
支持的服务:文件传送File Transfer;远程登录Remote login;计算机邮件Mail;网络文件系统(NFS);远程打印(Remote printing);远程执行(Remote execution);名字服务器(Name servers);终端服务器(Terminal servers)。
2. 端口
协议中提出了端口(port)的概念,用于标识网络主机上通信的软件进程。 端口实际上是一个抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序(即进程)通过系统调用与某端口建立关联(binding)后,传输层传给该端口的数据都被相应的应用进程所接收。端口又是在网络体系结构中应用进程访问传输服务的入口点SAP(Service Access Point服务访问点)。
在TCP/IP体系中,用于存储端口号长度为16bit ,取值范围0~65535,它用于存储本地软件进程,所以仅具有本地意义。通常,端口分为:熟知端口,取值范围0~1023,为常用应用进程指定的固定值;一般端口,取值范围1024~49151,供一般程序使用;动态端口:49152~65535供某些默认服务使用,如表1所示。
表1 常用进程和熟知端口
echo | 7 | 验证2台计算机连接有效性 |
daytime | 13 | 服务器当前时间文本描述 |
ftp | 20/21 | 21用于命令,20用户数据 |
telnet | 23 | 远程登录 |
smtp | 25 | 邮件发送 |
whois | 43 | 网络管理的目录服务 |
dns | 53 | 域名解析 |
tftp | 69 | 小文件传输 |
finger | 79 | 主机用户信息 |
http | 80 | HTTP |
pop3 | 110 | 邮局协议 |
nntp | 119 | 网络新闻传输协议, 发布Usenet新闻 |
snmp | 161 | 网络管理协议 |
rip | 520 | 路由协议 |
3. 套接字
套接字Socket原意是 “插座”,简单的说就是参与通信两方的一种约定,用套接字中的相关函数来完成通信过程。为了区分不同应用程序进程间的网络通信和连接,主要使用3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号,通过将这3个参数结合起来,与一个Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。通常的表示方式为:SOCKET=(传输协议,IP,Port)。
4 . Netstat
是DOS命令,是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息.Netstat用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。
可以通过执行Netstat /help获得该应用程序选项的相关帮助。
在Java语言中,实现TCP 套接字中有两个基础类,分别为:
l Socket类: 建立一个客户端标识
l ServerSocket类: 建立一个服务器端标识
5. ServerSocket
该类实现服务器socket,一个服务器socket等待网络上的连接请求。通常操作都是基于这个请求,并且会返回一个结果给请求连接者,其类描述如图2所示。
图2 ServerSocket类描述
ServerSocket构造方法有:
ServerSocket() 创建一个空的服务端socket; |
ServerSocket(int port) 在指定端口创建一个服务端socket,; |
ServerSocket(int port, int backlog) 在指定端口创建一个服务端socket和日志; |
ServerSocket(int port, int backlog, InetAddress bindAddr) |
6. Socket
该类实现一个客户端socket,这个socket表示在通信的两台设备之间的端点,其类描述如图3所示。
图3 Socket类描述
Socket构造方法有:
Socket() 创建一个空的客户端socket; |
Socket(InetAddress 创建一个连接指定远程地址和端口的客户端socket; |
Socket(InetAddress address, int port, InetAddress 在本地指定地址和端口,创建一个连接指定远程地址和端口的客户端socket; |
Socket(String 创建一个连接指定主机名称和端口的客户端socket; |
Socket(String host, int port, InetAddress 在本地指定地址和端口,创建一个连接指定远程主机名称和端口的客户端socket。 |
基本工作原理,如图所示。
1. 启动服务器端ServerSocket,监听指定端口;
2. 启动客户端Socket,连接服务器端Socket;
3. 服务器端Accept确认连接,建立通信通道;
4. 建立输入和输出流,进行通信;
5. 通信完毕,关闭Socket连接。
7. 多线程(Thread)
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。
Java里面有2个方法实现多线程,不论哪种方法都需要覆盖public void run()方法
1 继承 Thread类,比如
class MyThread extends Thread {
public void run() {
// 这里写上线程的内容
}
public static void main(String[] args) {
// 使用这个方法启动一个线程
new MyThread().start();
}
}
2 实现 Runnable接口
class MyThread implements Runnable{
public void run() {
// 这里写上线程的内容
}
public static void main(String[] args) {
// 使用这个方法启动一个线程
new Thread(new MyThread()).start();
}
}
一般鼓励使用第二种方法,因为Java里面只允许单一继承,但允许实现多个接口。第二个方法更加灵活。
类及方法
1. ServerSocket
常用方法 | |
Socket | accept() 接受客户端的连接请求; |
void | bind(SocketAddress |
void | close() 关闭该ServerSocket; |
InetAddress | getInetAddress() 获得该ServerSocket的本地地址; |
int | getLocalPort() 获得本地监听端口; |
int | getReceiveBufferSize() 获得接收缓存尺寸; |
int | getSoTimeout() 获得数据包超时时间; |
boolean | isClosed()判断ServerSocket是否关闭; |
void | setReceiveBufferSize(int size)设置接收缓存尺寸; |
void | setSoTimeout(int timeout) 以毫秒设置数据包超时时间; |
String | toString() 将地址和端口作为字符串返回。 |
2. Socket
常用方法 | |
void | bind(SocketAddress bindpoint) 绑定socket在本地; |
void | close() 关闭该socket; |
void | connect(SocketAddress |
void | connect(SocketAddress |
InetAddress | getInetAddress() 获得该socket连接的地址; |
InputStream | getInputStream() 获得该 socket的输入流; |
InetAddress | getLocalAddress() 获得该socket的本地地址; |
int | getLocalPort()获得该socket的本地端口; |
OutputStream | getOutputStream()获得该 socket的输出流; |
int | getPort()获得该 socket的远端端口; |
int | getReceiveBufferSize() 获得该Socket的接收缓存容量; |
int | getSendBufferSize()获得该Socket的发送缓存容量; |
int | getSoTimeout() 获得超时时间; |
boolean | isClosed() 判断该socket是否关闭; |
boolean | isConnected() 判断该socket是否连接; |
void | setKeepAlive(boolean on) 设置该socket的连接状态; |
void | setReceiveBufferSize(int size) 设置接收缓存容量; |
void | setSendBufferSize(int size) 设置发送缓存容量; |
void | setSoTimeout(int timeout) 设置毫秒级的超时时间; |
String | toString() 将该socket转换为字符串输出。 |
代码示例
对指定IP范围内主机上指定PORT范围进行连接测试
1 import java.net.*;
2 import java.io.*;
3
4 class myJava{
5 public static void main(String [] args){
6 String host = "222.24.16.";
7 String host_ip = null;
8 Socket cs = null;
9 for(int i=1; i<17; i++){
10 host_ip = host + i;
11 for(int j=0; j<65536; j++){
12 try{
13 cs = new Socket(host_ip, j);
14 System.out.println(host_ip + " : " + j);
15 }catch(Exception e){
16 System.err.println();
17 }
18 }
19 }
20 }
21 }
简单的单线程,一问一答式通信的TCP Server和TCP Client
服务端:
客户端:
1 //客户端
2 import java.io.*;
3 import java.net.*;
4 public class MyClient{
5 public static void main(String args[]) throws IOException{
6 Socket comSocket = null;
7 PrintStream out = null;
8 DataInputStream in = null;
9 try{
10 //建立socket连接
11 comSocket = new Socket("localhost", 1080);//相指定服务器的端口发出连接请求,注意服务器开放的TCP端口号
12 //分别对应服务器端的O/I流
13 in = new DataInputStream(comSocket.getInputStream());
14 out = new PrintStream(comSocket.getOutputStream());
15 }catch(UnknownHostException e){
16 System.err.println("Can't find the Server host");
17 System.exit(0);
18 }catch(IOException e){
19 System.err.println("Can't get I/O for the Connection");
20 System.exit(0);
21 }
22
23 DataInputStream stdIn = new DataInputStream(System.in);
24 String fromServer, fromUser;
25
26 while((fromServer = in.readLine()) != null){
27 System.out.println("Server:" + fromServer);
28 if(fromServer.equals("bye")) break;
29 fromUser = stdIn.readLine();
30 if(fromUser != null){
31 System.out.println("Client:" + fromUser);
32 out.println(fromUser);
33 }
34 }
35 out.close();
36 in.close();
37 stdIn.close();
38 comSocket.close();
39 }
40 }
探测目标计算机开放的TCP 端口
1 import java.io.*;
2 import java.net.*;
3
4 public class ScanPort{
5 public static void main(String args[]) throws IOException{
6 Socket comSocket = null;
7
8 for(int i=0;i<1024; i++){
9 try{
10 //建立socket连接
11 comSocket = new Socket("localhost", i);//发出连接请求
12
13 System.out.println("Can get I/O for the Connection, Port:" + i);
14 }catch(UnknownHostException e){
15 System.err.println("Can't find the Server host");
16 //System.exit(0);
17 }catch(IOException e){
18 System.err.println("Can't get I/O for the Connection, Port:" + i);
19 //System.exit(0);
20 }
21 }
22
23 try{
24 comSocket.close();
25 }catch(Exception e){}
26 }
27 }
TCP传输文件
服务端:
1 //采用TCP进行通讯,需要服务器和客户端两个部分,因此程序包含SendFileServer.java和SendFileClient.java两个部分。两个文件的IP,端口都在程序中指定, 传输的文件路径也在程序中指定
2 SendFileServer.java
3 import java.io.FileInputStream;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8 /*
9 * 用TCP进行文件传输
10 * 此文件为服务器文件
11 * 当接受到客户端的请求之后,先向其传输文件名
12 * 当客户端接受完毕之后,向客户端传输文件
13 * */
14 public class SendFileServer implements Runnable{
15 // 服务器监听端口
16 private static final int MONITORPORT = 12345;
17 private Socket s ;
18 public SendFileServer(Socket s) {
19 super();
20 this.s = s;
21 }
22 public static void server()
23 {
24 try {
25 // 创建服务器socket
26 ServerSocket ss = new ServerSocket(MONITORPORT);
27 while(true)
28 {
29 // 接收到一个客户端连接之后,创建一个新的线程进行服务
30 // 并将联通的socket传给该线程
31 Socket s = ss.accept();
32 new Thread(new SendFileServer(s)).start();
33 }
34 } catch (IOException e) {
35 // TODO Auto-generated catch block
36 e.printStackTrace();
37 }
38 }
39 /**
40 * @param args
41 */
42 public static void main(String[] args) {
43 // TODO Auto-generated method stub
44 SendFileServer.server();
45 }
46 @Override
47 public void run() {
48 // TODO Auto-generated method stub
49 byte[] buf = new byte[100];
50 OutputStream os=null;
51 FileInputStream fins=null;
52 try {
53 os = s.getOutputStream();
54 // 文件路径
55 String filePath = "/home/newton/cangjie.mp3";
56 // 文件名
57 String fileName = "cangjie.mp3";
58 System.out.println("将文件名:"+fileName+"传输过去");
59 //先将文件名传输过去
60 os.write(fileName.getBytes());
61 System.out.println("开始传输文件");
62 //将文件传输过去
63 // 获取文件
64 fins = new FileInputStream(filePath);
65 int data;
66 // 通过fins读取文件,并通过os将文件传输
67 while(-1!=(data = fins.read()))
68 {
69 os.write(data);
70 }
71 System.out.println("文件传输结束");
72 } catch (IOException e) {
73 // TODO Auto-generated catch block
74 e.printStackTrace();
75 }finally
76 {
77 try {
78 if(fins!=null) fins.close();
79 if(os!=null) os.close();
80 this.s.close();
81 } catch (IOException e) {
82 e.printStackTrace();
83 }
84 }
85 }
86 }
客户端:
1 import java.io.FileOutputStream;
2 import java.io.IOException;
3 import java.io.InputStream;
4 import java.net.InetSocketAddress;
5 import java.net.Socket;
6 /*
7 * 用TCP进行文件传输
8 * 此文件为客户端文件
9 * 连接上服务器之后,直接接受文件
10 *
11 * */
12 public class SendFileClient {
13 private static final String SERVERIP = "127.0.0.1";
14 private static final int SERVERPORT = 12345;
15 private static final int CLIENTPORT = 54321;
16 /**
17 * @param args
18 */
19 public static void main(String[] args) {
20 // TODO Auto-generated method stub
21 // 用来接受传输过来的字符
22 byte[] buf = new byte[100];
23 Socket s = new Socket();
24 try {
25 // 建立连接
26 s.connect(new InetSocketAddress(SERVERIP,SERVERPORT), CLIENTPORT);
27 InputStream is = s.getInputStream();
28 // 接收传输来的文件名
29 int len = is.read(buf);
30 String fileName = new String(buf,0,len);
31 System.out.println(fileName);
32 //接收传输来的文件
33 FileOutputStream fos = new FileOutputStream(fileName);
34 int data;
35 while(-1!=(data = is.read()))
36 {
37 fos.write(data);
38 }
39 is.close();
40 s.close();
41 } catch (IOException e) {
42 // TODO Auto-generated catch block
43 e.printStackTrace();
44 }
45 }
46 }