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编程的更多相关文章

  1. Java套接字Socket编程--TCP参数

    在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...

  2. Java套接字socket编程笔记

    相对于C和C++来说,Java中的socket编程是比较简单的,比较多的细节都已经被封装好了,每次创建socket连接只需要知道地址和端口即可. 在了解socket编程之前,我们先来了解一下读写数据的 ...

  3. Node.js开发入门—套接字(socket)编程

    Node.js的net模块提供了socket编程接口,方便我们利用较为底层的套接字接口来实现应用协议.这次我们看一个简单的回显服务器示例,包括服务端和客户端的代码. 代码 分服务器和客户端两部分来说吧 ...

  4. Java网络编程--套接字Socket

    一.套接字Socket IP地址标志Internet上的计算机,端口号标志正在计算机上运行的进程(程序). 端口号被规定为一个16位的0--65535之间的整数,其中,0--1023被预先定义的服务通 ...

  5. 套接字编程,创建套接字socket

    1.套接字地址结构: struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; 其中,成员sa_family表示套接字的协议族类型,对 ...

  6. 网络编程 套接字socket TCP UDP

    网络编程与套接字 网络编程 网络编程是什么: ​ 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 ​ 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...

  7. 网络编程(二)--TCP协议、基于tcp协议的套接字socket

    一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...

  8. 网络编程(二)——TCP协议、基于tcp协议的套接字socket

    TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...

  9. java网络编程之Socket编程

    概念 网络编程分为BIO(传统IO).NIO.AIO.Socket编程属于BIO这种传统IO. InetAddress java.net.InetAddress是JAVA中管理IP地址的类,常用 pu ...

随机推荐

  1. BZOJ 1000 A+B Problem (I/O)

    #include<cstdio> int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d&q ...

  2. ZYB's Premutation(有逆序数输出原序列,线段树)

    ZYB's Premutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  3. javaweb学习路之二--上传gitgub

    代码上传github 代码上传到github的步骤 第一步:申请github账号 https://github.com/注册账号 第二步:登录github,新建repository仓库,命名,创建 第 ...

  4. C# inherit

    Case:class A has a construct. class B is inherit from class A and B also has a construct. What's the ...

  5. 悬浮二维码 QQ ToTop

    //回顶部 <div id="lqdbe" style="position: absolute; visibility: visible; z-index: 1;  ...

  6. 密封关键字sealed

    在两种情况下使用: ·不想让别人继承:例如public sealed class Person{}; ·不想让子类重写自己的方法 例如: public class Person{ public vis ...

  7. Spring注解配置

    配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  8. PHP自练项目之发送短信内容

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 再次复习数据结构:c语言链表的简单操作

    最近呢,又要面临多次的数据结构与算法方面的试题了,而我呢,大概也重新温习c语言的基本要点快一个月了,主要是针对指针这货的角度在研究c语言,感觉又学到了不少. 现在c指针感觉知道点了,也就匆忙开展数据结 ...

  10. java和C#之间SOCKET通信的问题

    转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...