java Socket编程
一,网络编程中两个主要的问题
一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。
在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。
而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提 出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也 能及时得到服务。
二,两类传输协议:TCP;UDP
TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建 立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。
UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
比较:
UDP:1,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
2,UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
3,UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方
TCP:1,面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接
时间。
2,TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输的
数据。
3,TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。
应用:
1,TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
2,UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
三,Socket编程
在网络的双向链路当中,Socket可以表示链路当中的一端(服务器端或者客户端),通过Socket就可以进行两端的通信了。在一般的编程当中服务器端一般是用ServerSocket,客户端一般是用Socket.
从JAVA的API中了解一下Socket:

Socket的几种构造方法:
|
|
Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字 |
|
|
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 |
|
|
Socket(InetAddress host, int port, boolean stream) 已过时。 Use DatagramSocket instead for UDP transport. |
|
|
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。 |
|
|
Socket(Proxy proxy) 创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。 |
protected |
Socket(SocketImpl impl) 使用用户指定的 SocketImpl 创建一个未连接 Socket。 |
|
|
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。 |
|
|
Socket(String host, int port, boolean stream) 已过时。 使用 DatagramSocket 取代 UDP 传输。 |
|
|
Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。 |
Socket的简单用法:
Socket socket = new Socket("服务器IP" , "服务器端口号");这样就简单的像服务器发送请求了
如果请求通过了,通过socket来从服务器获取相应的输入流或则设置相应的输出流给服务器即可
ServerSocket的API解释:

相关构造方法:
ServerSocket() 创建非绑定服务器套接字。 |
ServerSocket(int port) 创建绑定到特定端口的服务器套接字。 |
ServerSocket(int port, int backlog) 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。 |
ServerSocket(int port, int backlog, InetAddress bindAddr) 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。 |
对ServerSocket中一些常用方法:
accept() 该方法监听客户端Socket的请求,请求通过后返回一个Socket(这个Socket不是客户端的Socket,而只是用于和客户端Socket进行对接的Socket)
做个如下比喻:
ServerSocket是一个公司,请求的Socket是客户,当客户去公司请求相关服务的时候,来到前台说明来意后,前台小妹妹就(accept)确认后你的信息后,
就安排了一个业务员(accept返回的Socket)来与你洽谈,业务员将相关服务数据给客户的话是要用业务员的OutPutStream ,而客户给业务员的数据对业务员
来说是InputStream , 对客户来说是OutputStream.所以说serverSocket和Socket之间是不直接进行通信的,而是ServerSocket的代表Socket和客户端
的Socket进行通信的
ServerSocket简单用法:
ServerSocket ss = new ServerSocket(port); port端口号一般要设置大于1023
注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才 能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,
ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。
Socket serventSocket = ss.accept();
在进行相应的数据流处理
下面通过一个简单的demo说明Socket ,
服务器端(创建一个java工程):
1 public class ServerSocketTest { 2 3 public static void main(String[] args) { 4 5 try { 6 ServerSocket ss = new ServerSocket(8081); 7 // 采用while循环是保证服务器一直开启 8 while (true) { 9 System.out.println("ServerSocketTest"); 10 Socket s = ss.accept(); 11 OutputStream os = s.getOutputStream(); 12 String str = "aaaaaaaaaaaaaaaaa"; 13 byte[] bData = str.getBytes("utf-8"); 14 os.write(bData); 15 os.close(); 16 s.close(); 17 } 18 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 23 } 24 }
上面的代码运行后你查看任务管理器当中有一条这个:

表示服务正在运行 , 如果你没有加while循环去重复监听客户端的请求,那么在请求一次过后,红框范围的服务进行就会消息了,后续的请求就不会有相应了
Android客户端(点击一个Button,打印出服务器返回来的数据):
1 public class MainActivity extends Activity { 2 3 private TextView tvTextView; 4 private Button btn; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main); 10 11 tvTextView = (TextView) findViewById(R.id.tv_show); 12 btn = (Button) findViewById(R.id.btn); 13 btn.setOnClickListener(new OnClickListener() { 14 15 @Override 16 public void onClick(View v) { 17 new Thread() { 18 @Override 19 public void run() { 20 try { 21 Socket socket = new Socket("222.18.162.132", 8081); 22 BufferedReader bufferedReader = new BufferedReader( 23 new InputStreamReader(socket 24 .getInputStream())); 25 26 OutputStream os = socket.getOutputStream(); 27 byte[] bStr = "client".getBytes("utf-8"); 28 os.write(bStr); 29 String str = bufferedReader.readLine(); 30 System.out.println("传过来的数据->" + str); 31 socket.close(); 32 bufferedReader.close(); 33 os.close(); 34 35 } catch (UnknownHostException e) { 36 e.printStackTrace(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 41 } 42 43 }.start(); 44 45 } 46 }); 47 48 } 49 50 }
打印出来的结果是:


浙公网安备 33010602011771号