socket网络编程
一、实现通信的条件
1、IP地址
IP具有唯一性
IP地址范围:0.0.0.0-255.255.255.255
本地IP地址:127.0.0.1或0.0.0.0
2、IP协议
Internet Protocol 互联网协议,为计算机网络相互连接进行通信而设计的协议
3、端口号
端口号包括逻辑端口和物理端口
物理端口是指连接物理设备之间的接口
逻辑端口是指逻辑上用于区分服务的端口
端口号只有整数,范围:0-65535
1024-5000分配给操作系统各个进程
大于5000的是其它软件分配的
二、TCP/IP协议
1、TCP协议
Transmission Control Protocol 传输控制协议
2、IP协议
Internet Protocol 互联网协议(网际互联协议)
三、TCP/IP五层模型
1、应用层
网络服务与最终用户的一个接口
协议有:HTTP FTP SMTP TFTP SNMP DNS TELNET HTTPS POP3 DHCP
2、传输层
定义传输数据的协议端口号,以及流程控制和差错校验
协议有:TCP UDP
3、网络层
进行逻辑地址寻址,实现不同网络之间的路径选择
协议有:ICMP IGMP IP(IPv4 IPv6) ARP RARP
4、数据链路层
建立逻辑连接,进行硬件地址寻址,差错校验等功能
5、物理层
建立、维护、断开物理连接。(由底层网络定义协议 )
四、TCP的三次握手
(1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认
(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态
(3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
五、socket套接字
1、socket套接字的定义
IP地址+端口号组成了socket,socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。
网络上具有唯一标识的IP地址和端口号组合在一起,才能构成唯一能识别的标识符套接字.。
socket原理机制:
- 通信两端都有socket
- 网络通信其实就是socket之间的通信
- 数据在两个socket间通过IO流传输
六、socket编程实现即时通讯
服务端:
public class ServerNode {
public static void main(String[] args) throws IOException, InterruptedException {
String readline = null;
String inTemp = null;
String turnLine = "\n";
final String client = "Client:";
final String server = "Server:";
//端口号
int port = 8081;
//1 创建ServerSocket,监听端口8081
ServerSocket serverSocket = new ServerSocket(port);
//2 调用服务器的accept方法,接受来自客户端的连接请求。在接收到客户端连接请求之前,此方法会进行阻塞(程序会在这等待),当有申请连接时会建立连接并返回一个socket
Socket socket = serverSocket.accept();
//3 创建服务端输入流:获取系统输入的数据
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in));
//4 创建客户端输入流:获取客户端传输的数据
BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//5 创建输出流:用于向客户端返回数据
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
while(readline != "bye"){//当服务端系统输入bye时,终止连接
//6 读取客户端输入流
inTemp = socketIn.readLine();
System.out.println(client + turnLine + inTemp);
System.out.println(server);
//7 服务端系统输入
readline = systemIn.readLine();
//8 向客户端返回数据
socketOut.println(readline);
/*
* println() 和 write()的区别:
* write方法只会写入字符,不会写入换行符和回车符
* println方法意思是写入一行数据,会自带换行符
*
* 当readLine()方法只有读取到 \n 或者 \r 的时候,代表数据读取完毕
* 否则会一直继续读取输入流的数据,直到有换行符出现
* 如果用write方法,会造成程序执行阻塞
*/
socketOut.flush(); //赶快刷新使Client收到,也可以换成socketOut.println(readline, ture)
}
systemIn.close();
socketIn.close();
socketOut.close();
socket.close();
serverSocket.close();
}
}
客户端:
public class ClientNode {
public static void main(String[] args) throws IOException, InterruptedException {
String readline = null;
String inTemp = null;
String turnLine = "\n";
final String client = "Client:";
final String server = "Server:";
//服务端端口号
int port = 8081;
/*
* 服务端ip地址
*/
// byte ipAddressTemp[] = {127, 0, 0, 1};
// InetAddress ipAddress = InetAddress.getByAddress(ipAddressTemp);
//首先直接创建socket,端口号1~1023为系统保存,一般设在1023之外
Socket socket = new Socket("127.0.0.1", port);
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in));
BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
while(readline != "bye"){
//客户端:读取系统字节流
System.out.println(client);
readline = systemIn.readLine();
//客户端:输出流向服务端发送数据
socketOut.println(readline);
socketOut.flush(); //赶快刷新使Server收到,也可以换成socketOut.println(readline, ture)
//读取服务端返回的数据
inTemp = socketIn.readLine();
System.out.println(server + turnLine + inTemp);
}
//关闭资源
systemIn.close();
socketIn.close();
socketOut.close();
socket.close();
}
}