概念:socket好比一部电话机,两个程序在网络上通过一个双向链路进行通信,这个双向链路的每一端成为一个socket。
套接字接口socket是传送层提供的网络进程接口,通信的主动方是客户端,它利用socket向服务器(接收方)发出请求,服务器接受客户端发出的请求,返回服务结果。
进程之间的通信首先要建立各自的套接口,套接口同一台网络计算机的一个特定进程关联,与进程建立的套接口绑定在一起。客户程序必须事先知道自己要求连接的那个服务进程的IP地址和端口号,程序员在创建自己的应用服务程序时一般自己先指定一个端口号,亦可以由系统分配一个端口号。客户通过这个端口号连接该服务进程。客户端应用进程像服务进程一样,也有自己的端口号,通过该端口客户端应用进程与服务进程通信。
利用socket进行网络通信:
利用socket进行网络通信的过程包括建立socket链接,获得输入/输出流,读/写数据和关闭socket四个步骤。在Java的软件包java.net中提供了进行这些操作的方法。Java.net中提供了两个类:socket和seversocket。它们分别用于服务器端和客户端的socket通信,进行网络通信的方法也都封装在这两个类中。
在客户/服务器模式当中,客户首先向服务器发出某种请求,然后等待服务器响应该请求。因此客户端要主动的创立socket套接字,服务器端收到了客户的请求,也会建立与用户连接的socket。
socket类的3种测试方法:1.isClosed():检测socket是否关闭2.isConnected()检测是否连接到远程主机3.isBound()检测是否与本地端口绑定
如果进程A输出数据,进程B读入数据,A要告诉B输出结束则采用以下方式:
(1)如果A和B交换的是字符流并且是一行一行的读取,可以事先设定一个字符串为结束标志。当这个字符串被读到时,B就停止继续读数据。
(2)进程A先发送一个消息告诉进程B所发送的正文的长度,然后再发送正文。进程B先获得进程A所发正文的长度,读取这个长度的字节后即停止读取。
(3)进程A发完所有数据后关闭socket,当进程B读入了进程A所发送的所有数据之后,再次执行输入流的read()方法时返回-1,如果执行readBuffer的readline()方法时,则返回null。
(4)当调用Socket中的close方法关闭时,他的输入流和输出流也都被关闭。如果希望仅关闭其中之一,就要用
shutdownInput()和shutdownoutput这样的半关闭方法。进程B读取时进程A的输出流已关闭,就会读到文件结尾。
socket和seversocket构造方法:
Serversocket(int port) //port表示端口号
Seversocket(int port,int count) //count表示服务器所能接受连接的最大数目
创建流套接字并将其连接到指定的IP地址的指定端口号
Socket(String host,int port) //表示服务器端的主机名
Socket(String host,int port,InetAddress localAddr,int localPort) //创建套接字并将其连接到指定远程端口上的指定远程主机
Socket(InetAddress address,int port,InetAddress localAddr,int localPort)//创建套接字并将其连接到指定的远程端口上的远程地址
TCP服务器端
绑定IP与端口号:首先是进行IP查询:快捷键win+r----->输入cmd+回车----->输入ipconfig命令
也可以编写程序查询IP地址:
package D;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
public class MyHost {
public static void main(String args[]) {
InetAddress ip = null;
try {
ip = InetAddress.getByName("localhost");
System.out.println("主机名:" + ip.getHostName());
System.out.println("主机IP地址:" + ip.getHostAddress());
System.out.println("本机IP地址:" + ip.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
创建ipaddress 类 ,传入一个4byte的数组,就可以保存IP地址的四位
Endpoint对端口和IP进行了一层封装
开始监听,等待客户端连接
listen将主动套接口转为被动套接口,等待用户创立连接。
暂停当前进程,直到有一个客户端连接过来
package D;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPDemo {
public static void main(String args[])throws Exception{
System.out.println("我是服务端");
ServerSocket ss=new ServerSocket(8000);
//等待客户端连接(阻塞)
Socket s=ss.accept();
//得到输入流
InputStream is=s.getInputStream();
//输入字节流
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String strline=br.readLine(); //读行
System.out.println("客户端说:"+strline);
//得到输出流
OutputStream os=s.getOutputStream();
//输出字节流
PrintStream ps=new PrintStream(os,true);
String a="客户端你好~";
//向客户端发送消息
ps.println(a);
}
}
TCP客户端
首先也是要创建一个socket
AddressFamily指定用来指定地址的寻址方式
发起建立连接的请求
定位一个服务器端
Concle.writelen提供一个格式化的提示,然后从控制台读取一行文本
package D;
import java.io.*;
import java.net.Socket;
public class TCPClient {
public static void main(String args[])throws Exception{
System.out.println("你好我是客户端");
//与服务器端口连接
Socket sk=new Socket("localhost",9000);
//得到输入流
OutputStream os=sk.getOutputStream();
//输出字符流,布尔值为真表示每当写入一个字节数组缓冲区就刷新一下
PrintStream ps=new PrintStream(os,true);
ps.println("你好服务器端");
//得到输入流
InputStream is=sk.getInputStream();
//输入字节流
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
System.out.println("服务器端说:"+br.readLine());
}
}