Socket编程

Socket编程

1. Socket简介

Socket通常称作“套接字”,用于描述IP和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提各种服务。每种服务都打开一个socket,并绑定到一个端口上,不同的端口对应于不同的服务。

2. Socket编程

网络编程就是直接或间接的通过网络协议与其他计算机进行通信。

其中最重要的两点:

1.如何准确定位到网络上的另外一台主机

2.找到主机之后如何可靠高效的传输数据

2.1 IP、端口

IP地址标识了Internet上的计算机,端口号标识正在运行的进程。

IP和端口号组合则可以得出一个网络套接字。

端口号为一个16位(即2byte)的整数,范围为0~65535。其中0~1023被预定义的通信服务占用。为了避免冲突,我们自己的程序应该使用1024~65535之间的。

2.2 InetAddress

Internet上的主机有两种方式表示其地址

1). 域名: www.ztdjt.com

2). IP27.151.0.99

java.net.InetAddress常用方法:

getHostName()  //得到域名

getHostAddress()  //得到IP地址

//得到本地地址

InetAddress localAddress = socket.getLocalAddress();

//得到本地的端口

int localPort = socket.getLocalPort();

//得到远端的地址

InetAddress remoteAddress = socket.getInetAddress();

//得到远端的端口

int remotePort = socket.getPort();

 

3. TCP

TCP(Transmission Control Protocol)传输控制协议,是面向连接的运输层协议。应用程序在使用TCP协议通信之前,必须建立起TCP连接,在传输完毕后,释放已建立连接。其中通信的两个应用一个是服务器进程,另一个是客户端进程。

3.1 TCP通信过程

 

1. 第一次握手:建立连接,客户端发送到syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

2. 第二次握手:服务器接收到syn包,必须确认客户的SYNack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

3. 第三次握手:客户端接收到服务器的SYN+ACK包,向服务器发送确认包ACKack=ack+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态。

4. 完成三次握手后,客户端和服务端就可以开始传送数据了。

3.2 TCP网络编程

1. Server端监听ServerSocket

java.net.ServerScoket是运行于服务端的应用程序。

//创建ServerSocket并申请服务端口为8888

ServerSocket server = new ServerSocket(8888);

//侦听客户端连接,这个方法会阻塞,直到某个socket连接

Socket socket = server.accept();

 

 

2Client端连接server

创建Socket的同时就发起连接,若连接异常就会抛出异常,需要传入服务端的的地址和端口号

//参数1:服务端的IP地址,参数2:服务端的服务端口

Socket socket = new Socket("127.0.0.1", 8888);

 

3.获取网路输入流、网络输出流

通过socket获取输入流和输入流,这两个方法时使用Socket通讯的关键方法。封装了TCP协议的Socket是基于流进行通讯的,所以在创建了双方连接后,只需要获取相应的输入与输出流即可实现通讯。

//得到套接字的输入流

InputStream in = socket.getInputStream();

//得到套接字的输出流

OutputStream out = socket.getOutputStream();

 

4. 关闭socket

通讯完毕后,要关闭Socket以释放系统资源。当关闭了该套接字后也会同时关闭由此获取的输入和输出流。

socket.close()

 

5. 编程分为服务端和客户端

 

1). 服务端创建ServerSocket,绑定到指定端口

2). 服务端调用accept(),监听端口,等待客户端来连接

3). 客户端创建Socket并指定服务端的IP地址及端口,与服务端建立连接

4). 服务端accept发现客户端连接后,获取对应该客户端的Socket

5). 调用SocketgetOutputStreamgetInputStream获取网络输出流和输入流,开始发送和接收数据

6). 通讯结束后,关闭连接

服务端程序:

/**

 * Server端应用程序

 * @author jmcfeng

 */

public class Server {

public static void main(String[] args){

ServerSocket server = null;

try {

//创建ServerSocket并申请服务端口为8888

server = new ServerSocket(8888);

System.out.println("服务端启动...");

//侦听客户端连接

Socket socket = server.accept();

//客户端连接后,通过该Socket与客户端交互

//得到一个输入流,用于读取客户端发送过来的数据

InputStream is = socket.getInputStream();

BufferedReader br = new BufferedReader(new InputStreamReader(is));

//读取客户端发送的消息

String msg = br.readLine();

System.out.println("客户端说:" + msg);

//得到一个输出流,用于向该客户端发送数据

OutputStream os = socket.getOutputStream();

//是否自动刷新

PrintWriter printer = new PrintWriter(new OutputStreamWriter(os, "UTF-8"), true);

//向客户端发送数据

printer.println("你好客户端!");

} catch (IOException e) {

e.printStackTrace();

} finally{

try {

server.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

 

客户端:

/**

 * Client端应用程序

 * @author jmcfeng

 */

public class Client {

public static void main(String[] args) {

Socket socket = null;

try {

//和服务端建立一个连接

socket = new Socket("127.0.0.1", 8888);

//得到一个输出流,向服务端发送数据

OutputStream out = socket.getOutputStream();

OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");

PrintWriter printer = new PrintWriter(osw, true);

printer.println("你好服务端");

//得到一个输入流,用于读取来自服务端的数据

InputStream in = socket.getInputStream();

BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));

String str = reader.readLine();

System.out.println("服务端说:" + str);

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

//关闭连接

if(socket != null){

try {

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

 

4. UDP

UDP(User Datagram Protocol)用户传输控制协议,是面向无连接的运输层协议。在使用UDP协议通信之前,不需要建立连接。

4.1 UDP网络编程

UDP数据包通过数据报套接字java.net.DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

 

4.1.1 DatagramPacket

java.net.DatagramPacketUDP数据包基于IP、端口建立的。数据包中字节数限制为65536 – 8byte(头信息需要占8字节)。

 

1. 创建接收包

构造函数:

DatagramPacket(byte buf[], int length)

将数据包中Length长的数据装进Buf数组

 

DatagramPacket(byte buf[], int offset, int length)

将数据包中从offest开始、length长的数据装进buf数组

 

2. 创建发送包

构造函数:

DatagramPacket(byte buf[], int length, InetAddress address, int port)

buf数组中取出length长的数据创建数据包对象,目标是地址address端口port

 

DatagramPacket(byte buf[], int offset, int length,

                          InetAddress address, int port)

buf数组中取出offset开始的、length长的数据包创建数据包对象,目标是地址adderss端口port

 

4.1.2 DatagramSocket

java.net.DatagramSocket:用于接收和发送UDPSocket实例

 

1. 服务端接收

DatagramSocket(int port)

创建实例,并固定监听Port端口的报文。

 

 

void receive(DatagramPacket p)

接收数据报文到p中,receive方法产生”阻塞”。会一直等待知道有数据被读取到。

 

2. 客户端发送

DatagramSocket()

无参构造方法用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。程序会让操作系统分配一个可用端口。

 

void send(DatagramPacket p)

发送报文到目的地

 

Server端:

/**

 * UDP Server端程序

 * @author jmcfeng

 */

public class Server {

public static void main(String[] args) {

DatagramSocket socket = null;

try {

//监听8888端口

socket = new DatagramSocket(8888);

byte[] data = new byte[1024];

//创建接收包

DatagramPacket packet = new DatagramPacket(data, data.length);

//读取发送过来的数据,产生阻塞

socket.receive(packet);

//将包中的数据

String str = new String(packet.getData(), 0, packet.getLength());

System.out.println("接收到数据包:" + str);

} catch (SocketException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally{

//关闭以释放资源

socket.close();

}

}

}

 

 

 

 

Client端:

/**

 * UDP Client

 * @author jmcfeng

 */

public class Client {

public static void main(String[] args) {

DatagramSocket socket = null;

try {

//创建socket

socket = new DatagramSocket();

byte[] data = "你好服务器,你有freestyle么。".getBytes();

//创建发送包

DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 8888);

//发送数据

socket.send(packet);

} catch (SocketException e) {

e.printStackTrace();

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

//关闭以释放资源

socket.close();

}

}

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值