[置顶] Java套接字Socket编程
1)概念
网络编程基本模型就客户端到服务器的模型,也就是我们常见的C/S模型。简单的说就是两个进程间相互通信的过程。即通信双方一方作为服务器等待客户端提出请求并给以回应,另一方作为客户端向服务器提出请求。服务器一方一般作为守护进程始终运行,监听网络端口,一旦监听到客户请求,就启动一个服务进程或线程来响应该客户端,同时继续监听端口等待其他客户端的连接。
2)两种传输协议
(1) TCP 传输控制协议
TCP是Transfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议基础上通信。服务器端和客户端通过一对socket进行连接,一旦连接成功,她们就可以进行双向数据传输了。
Java中,这些操作被封装到两个类中:Socket、ServerSocket分别用于完成客户端和服务器端的套接字的操作。
1) 面向连接协议,在socket之间进行数据传输之前必须建立连接,所以TCP中需要连接时间。
2) TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按照统一的格式传输最大的数据。
3) TCP是一个可靠的协议,确保接收方完全正确的获取发送方所发送的全部数据。
4) 主要用于远程连接Telnet和文件传输FTP等对传输质量要求高程序中。
(2) UDP 用户数据报协议
UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址和目的地址,在网络上以任何可能的路径传输到达目的地。由于UDP是一种无连接的协议,所以数据报能否到达目的地、到达目的地的时间以及顺序都不能保证。所以UDP协议是不可靠的。
1) 每个数据报中都给出了完整的地址信息,因此需要建立发送方和接收方的连接。
2) UDP传输数据时是有大小限制的,每个被传输的数据报都必须限定在64KB之内。
3) UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
4) 通常用于局域网高可靠性的分散系统中client/server应用程序。如:音视频会议系统,ts流传输等等。
3)套接字Socket
网络上两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端为一个socket。Socket通常用来实现客户方和服务方的连接。Socket主要由一个IP地址和一个端口号来确定。在Java中Socket编程主要指基于TCP/IP协议的网络编程。
(1) Stream socket数据流套接字
客户端编程:
1) 新建一个套接字
2) 为套接字建立一个输入流和输出流
3) 根据协议从套接字读入或向套接字写入
4) 关闭套接字的输入、输出流
服务器端程序:
1) 创建一个服务器型套接字和一个普通套接字
2) 将服务器型套接字处于监听状态,并把结果返回给普通套接字
3) 为该普通套接字创建输入和输出流
4) 从输入和输出流读入或写入字节数据,进行相应处理
5) 完成后关闭所有对象,包括服务器型套接字、普通套接字、输入流输出流等。
创建Socket:
java中在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。
Socket的构造方法:
- Socket(SocketImpl impl)
- Socket(String host, int port);
- Socket(InetAddress address, int port);
- Socket(String host, int port, InetAddress localAddr, int locolPort);
- Socket(InetAddress address, int port, InetAddress locolAddr, int locolPort);
其中address、host和port分别用来表示对方的ip地址、主机号和端口号,而stream是指定socket是stream流套接字还是Datagram数据报套接字。如果创建Socket时发生错误,将产生IOException,在程序中需要对之作出处理。
这里的InetAddress是一个表示互联网协议Ip地址的类,继承于Object,实现了Serializable接口。常用方法:
byte[] getAddress() // 返回这个对象的原始IP地址
static InetAddress getByAddress(byte[] addr) // 根据给定的IP地址,返回InetAddress类
static InetAddress getByName(String name) // 根据给定主机名确定IP地址类
static InetAddress getByAddress(String host, byte[] addr) // 根据主机名和IP地址确定InetAddress
String getHostAddress() // 文本表现形式返回IP地址字符串
String getHostName() // 返回IP地址的主机名
介绍另外一个类InetSocketAddress,实现了IP地址+端口号来确定一个对象。它继承于SocketAddress,构造函数如下:
InetSocketAddress(InetAddress addr, int port)
InetSocketAddress(int port)
InetSocketAddress(String hostname, int port)
Socket提供的常用方法:
- void bind(SocketAddress bindpoint)
- bool isBound()
- void close()
- bool isClosed()
- viod connect(SocketAddress endpoint, int timeout)
- bool isConnected()
- InetAddress getInetAddress()
- int getPort()
- InputStream getInputStream()
- OutputStream getOutputStream()
- InetAddress getLocalAddress()
- int getLocalPort()
Demo: 下面是一个客户端程序,负责向本地127.0.0.1:8889写入数据,然后再读取返回来的消息。
- try {
- Socket echoSocket = new Socket("127.0.0.1", 8889);
- OutputStream os = echoSocket.getOutputStream(); // 得到套接字的输出流
- DataInputStream is = new DataInputStream(echoSocket.getInputStream());
- int n;
- String responseLineString;
- while((n=System.in.read())!=-1) {
- os.write((byte)n);
- if(n == '\n'){
- os.flush();
- responseLineString = is.readLine();
- System.out.println("echo:" + responseLineString);
- }
- }
- os.close();
- is.close();
- echoSocket.close();
- } catch (UnknownHostException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
服务器端程序:对于客户端发送过来的数据原封不动的返回给客户端。
- try {
- ServerSocket serverSocket = new ServerSocket(4000, 10); // 4000端口
- System.out.println("Being accept...");
- Socket clientSocket = serverSocket.accept();
- // 获得输入流
- DataInputStream iStream = new DataInputStream(clientSocket.getInputStream());
- // 获得输出流
- PrintStream oStream = new PrintStream(new BufferedOutputStream(clientSocket.getOutputStream(), 1024), false);
- String inputLine;
- while((inputLine = iStream.readLine()) != null) {
- for(int i = 0; i < inputLine.length(); i++) {
- oStream.write((byte)inputLine.charAt(i)); // 原封不动的返回
- }
- oStream.write((byte)'\n');
- oStream.flush();
- System.out.println("Receive:"+inputLine);
- }
- oStream.close();
- iStream.close();
- clientSocket.close();
- serverSocket.close();
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
这里介绍的C/S程序只能实现简单的Server和一个Client之间交互,实际应用中,往往是在服务器上运行一个永久的程序,它可以接受来自多个客户端的请求,提供相应的服务。为了实现在服务器方给多个客服端提供服务的功能,需要用到多线程机制。服务器在指定端口上监听是否有客户请求,一旦监听到客户请求,服务器会立即启动一个专门的服务线程来响应客户端,而服务器又马上进入监听状态,继续等待下一个客户的到来。
(2) Datagram socket 数据报套接字
在TCP/IP协议的传输层除了TCP协议之外还有一个UDP协议,相比而言UDP应用一般用在需要很强的实时交互性的场所,如网络游戏、视频会议等。
在java.net包中提供了两个类DatagramSocket和DatagramPacket用来支撑数据报通信,其中DatagramSocket用于在程序之间建立传送数据报的通信连接,而DatagramPacket则用来表示一个数据报。
DatagramSocket用于创建数据报套接字,并绑定到指定的本地地址上。如DatagramSocket skt = new DatagramSocket(null); skt.bind(new InetSocketAddress(8888)) 等价于: DatagramSocket skt = new DatagramSocket(8888)
DatagramSocket的构造方法:
- protected DatagramSocket() // 绑定到本地主机任何可用端口上
- protected DatagramSocket(DatagramSocketImpl impl)
- protected DatagramSocket(int port)
- protected DatagramSocket(int port, InetAddres laddr)
- protected DatagramSocket(SocketAddr bindaddr)
其中port指定socket所使用的本地端口号,如果未指定则socket随机选择一个本地可用的端口,laddr表示一个可用的本地IP地址。
常用的方法:
- void bind(SocketAddress addr)
- boolean isBound()
- void close()
- boolean isClosed()
- void connect(InetAddress address, int port)
- void connect(SocketAddress addr)
- void disconnect()
- SocketAddress getLocalSocketAddress()
- InetAddress getInetAddress()
- int getPort()
- InetAddress getLocalAddress()
- int getLocalPort()
- bool isConnected()
- void receive(DatagramPacket pkt)
- void send(DatagramPacket pkt)
注意用数据报方式编写C/S程序时,无论是在客户端还是服务端,首先都需要建立一个DatagramPacket对象作为传输数据的载体。
DatagramPacket 用来表示数据包,用来实现无连接的包投递服务,每一条报文仅根据改包中包含的信息从一台机器路由到另一台机器。
构造函数:
- DatagramPacket(byte[] buf, int length) // 构造接收包
- DatagramPacket(byte[] buf, int offset, int length)
- // 下面这几个都是根据给定的地址和端口号来构造发送包
- DatagramPacket(byte[] buf, int length, InetAddress address, int port)
- DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
- DatagramPacket(byte[] buf, int offset, int length, SocketAddress addr)
- DatagramPacket(byte[] buf, int length, SocketAddress addr)
常用的方法:
- InetAddress getAddress()
- byte getData()
- int getLength()
- int getOffset()
- int getPort()
- SocketAddress getSocketAddress()
- void setAddress(InetAddress iaddr) // 设置发往的那台机器IP
- void setData(byte[] buf) // 设置包缓冲区
- void setData(byte[] buf, int offset, int length)
- void setLength(int len)
- void setPort()
- void setSocketAddress(SocketAddress address)
一个简单的客户端代码:
- int port;
- InetAddress address;
- DatagramSocket socket;
- DatagramPacket packet;
- byte[] sndBuf = new byte[1024];
- socket = new DatagramSocket();
- port = Integer.parseInt(args[1]);
- address = InetAddress.getByName(arg[0]);
- packet = new DatagramPacket(sndBuf, 1024, address, port);// 目的地址和端口号
- socket.send(packet);
- packet = new DatagramPacket(sndBuf, 1024);
- socket.receive(packet); // 阻塞直到接收到一个数据帧
- String received = new String(packet.getData(), 0);
- System.out.println("Receive:" + received);
- socket.close();
服务器端程序:
- public class UdpEchoServer {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- new ServerThread().start();
- }
- class ServerThread extends Thread {
- private DatagramSocket socket = null;
- private DatagramPacket packet = null;
- private DataInputStream inputStream;
- public ServerThread() {
- // TODO Auto-generated constructor stub
- super("ServerThread");
- try {
- socket = new DatagramSocket();
- System.out.println("ServerThread listen on port:" + socket.getLocalPort());
- } catch (Exception e) {
- // TODO: handle exception
- System.out.println("Could not create datagram socket");
- }
- this.openInputFile();
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- if(socket == null) {
- return;
- }
- while(true) {
- try {
- byte[] buf = new byte[1024];
- String dateString = null;
- packet = new DatagramPacket(buf, 1024);
- socket.receive(packet);
- InetAddress address = packet.getAddress();
- int port = packet.getPort();
- System.out.println("Get a packet from:" + address.toString());
- if(inputStream != null) {
- dateString = getNextLine();
- dateString.getBytes(0, dateString.length(), buf, 0);
- packet = new DatagramPacket(buf, buf.length, address, port);
- socket.send(packet);
- }
- } catch (Exception e) {
- // TODO: handle exception
- System.out.println("Exception:" + e);
- e.printStackTrace();
- }
- }
- }
- @Override
- protected void finalize() {
- if(socket != null) {
- socket.close();
- socket = null;
- System.out.println("Closing datagram socket");
- }
- }
- void openInputFile() {
- try {
- inputStream = new DataInputStream(new FileInputStream("C:\\test.txt"));
- } catch (Exception e) {
- // TODO: handle exception
- System.out.println("Open test.txt file error");
- }
- }
- String getNextLine() {
- String returnString = null;
- try {
- if((returnString = inputStream.readLine()) == null) {
- inputStream.close();
- this.openInputFile();
- returnString = inputStream.readLine();
- }
- } catch (IOException e) {
- // TODO: handle exception
- System.out.println("Error");
- }
- return returnString;
- }
- }
- }
(3) Raw socket 原始套接字
原始套接字可以用来发送和接收IP层以上的原始数据报,如ICMP,TCP,UDP等,一般用的比较少,这里就不分析。
[置顶] Java套接字Socket编程的更多相关文章
- Java套接字Socket编程--TCP参数
在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...
- Java套接字socket编程笔记
相对于C和C++来说,Java中的socket编程是比较简单的,比较多的细节都已经被封装好了,每次创建socket连接只需要知道地址和端口即可. 在了解socket编程之前,我们先来了解一下读写数据的 ...
- Node.js开发入门—套接字(socket)编程
Node.js的net模块提供了socket编程接口,方便我们利用较为底层的套接字接口来实现应用协议.这次我们看一个简单的回显服务器示例,包括服务端和客户端的代码. 代码 分服务器和客户端两部分来说吧 ...
- Java网络编程--套接字Socket
一.套接字Socket IP地址标志Internet上的计算机,端口号标志正在计算机上运行的进程(程序). 端口号被规定为一个16位的0--65535之间的整数,其中,0--1023被预先定义的服务通 ...
- 套接字编程,创建套接字socket
1.套接字地址结构: struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; 其中,成员sa_family表示套接字的协议族类型,对 ...
- 网络编程 套接字socket TCP UDP
网络编程与套接字 网络编程 网络编程是什么: 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...
- 网络编程(二)--TCP协议、基于tcp协议的套接字socket
一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...
- 网络编程(二)——TCP协议、基于tcp协议的套接字socket
TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...
- java网络编程之Socket编程
概念 网络编程分为BIO(传统IO).NIO.AIO.Socket编程属于BIO这种传统IO. InetAddress java.net.InetAddress是JAVA中管理IP地址的类,常用 pu ...
随机推荐
- Android PNG渐变背景图片失真问题 getWindow().setFormat(PixelFormat.RGBA_8888);
最近一个困扰很久的问题,渐变效果的png图片,设置为控件图片或background时,在eclipse上看着没有什么问题,但是在设备上运行时,可以看到明显的一圈圈的轮廓线,图片严重失真.在网上goog ...
- android Json解析详解(详细代码)
JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行数据 ...
- Java中String、StringBuilder以及StringBuffer
原文出处: 海子 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String.StringBuilder和StringBuffe ...
- 让你提前认识软件开发(19):C语言中的协议及单元測试演示样例
第1部分 又一次认识C语言 C语言中的协议及单元測试演示样例 [文章摘要] 在实际的软件开发项目中.常常要实现多个模块之间的通信.这就须要大家约定好相互之间的通信协议,各自依照协议来收发和解析消息. ...
- 如何设计一个 iOS 控件?(iOS 控件完全解析)
前言 一个控件从外在特征来说,主要是封装这几点: 交互方式 显示样式 数据使用 对外在特征的封装,能让我们在多种环境下达到 PM 对产品的要求,并且提到代码复用率,使维护工作保持在一个相对较小的范围内 ...
- Android 中文API (65) —— BluetoothClass[蓝牙]
前言 本章内容是android.bluetooth.BluetoothClass,为Android蓝牙部分的章节翻译.用于描述远端设备的类型,特点等信息,通过getBluetoothClass()方法 ...
- SharePoint 2010 BCS - 简单实例(一)数据源加入
博客地址 http://blog.csdn.net/foxdave 本篇基于SharePoint 2010 Foundation. 我的数据库中有一个病人信息表Patient,如今我就想把这个表中的数 ...
- document.execCommand()函数可用参数解析
隐藏在暗处的方法-execCommand() 关键字: javascript document document.execCommand()方法可用来执行很多我们无法实现的操作. execComman ...
- No.2小白的HTML+CSS心得篇
今天要强调的重点是分析把握好HTML标签的两个方面: 1.标签的用途(用途指的是用来干什么,有什么作用)在专业术语叫作 语义化. 举个列子:<br/> 换行的作用 见了它就明白它的语义就是 ...
- Python之路:Python 基础(二)
一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 1==1: name = 'lenliu' print name 下面的结论对吗?(对) 外层变量,可以被 ...