Java 网络编程
关键的两个类
Socket类
该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。
构造方法
public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。
Socket client = new Socket("127.0.0.1", 6666);
这里的参数中的ip地址和端口不是设定本机的,而是设定的服务器的ip和服务器中服务端的端口号
成员方法
public InputStream getInputStream(): 返回此套接字的输入流。- 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
- 关闭生成的InputStream也将关闭相关的Socket。
public OutputStream getOutputStream(): 返回此套接字的输出流。- 如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
- 关闭生成的OutputStream也将关闭相关的Socket。
public void close():关闭此套接字。- 一旦一个socket被关闭,它不可再使用。
- 关闭此socket也将关闭相关的InputStream和OutputStream 。
public void shutdownOutput(): 禁用此套接字的输出流。- 任何先前写出的数据将被发送,随后终止输出流。
ServerSocket类
ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。
构造方法
public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。
ServerSocket server = new ServerSocket(6666);
这里的端口号指的是本地服务的端口号,客户端通过这个端口号找到相应的服务
成员方法
public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。
一个简单的TCP通信案例
服务端
public class MyTcpServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(6666);
while (true){
Socket clientSocket = server.accept();
System.out.println(clientSocket);
new Thread(()->{
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()
) {
deal(inputStream,outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
private static void deal(InputStream inputStream, OutputStream outputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
String str = null;
str = reader.readLine();
System.out.println(str);
writer.write("收到!");
writer.newLine();
writer.flush();
System.out.println("deal finish!");
}
}
客户端
public class MyTcpClient {
public static void main(String[] args) throws IOException {
try(Socket socket = new Socket("localhost", 6666);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
){
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("r u ok?");
bufferedWriter.newLine();
bufferedWriter.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String str= null;
str = reader.readLine();
System.out.println(str);
}
}
}
注:一开始写代码的时候设置读取数据的时候使用的循环,但是使用循环就会产生,再读取完数据之后依然会继续等待直到这个连接结束(因为readLine方法会阻塞)
所以如果两边都有使用循环获取文字就会产生死锁,导致不能继续进行下去,见下方
发送多行数据的程序
一个错误的案例
服务端
public class MyTcpServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(6666);
while (true){
Socket clientSocket = server.accept();
System.out.println(clientSocket);
new Thread(()->{
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()
) {
deal(inputStream,outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
private static void deal(InputStream inputStream, OutputStream outputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
String str = null;
while ((str = reader.readLine())!=null){
System.out.println(str);
}
writer.write("收到!");
writer.newLine();
writer.flush();
System.out.println("deal finish!");
}
}
客户端
public class MyTcpClient {
public static void main(String[] args) throws IOException {
try(Socket socket = new Socket("localhost", 6666);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
){
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello!");
bufferedWriter.newLine();
bufferedWriter.write("r u ok?");
bufferedWriter.newLine();
bufferedWriter.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String str= null;
while ((str = reader.readLine())!=null){
System.out.println(str);
}
}
}
}
然后就会发生之前讲过的问题
- 客户端在发送完数据之后给服务端,服务端输出了客户端给的数据,
- 但是服务端的循环还没跳出 在下一次循环判断的时候,阻塞了,就不能执行下面发送给客户端数据的代码
- 客户端此时也在等待服务端发送数据,而服务端等待客户端发送数据,于是就导致程序卡住了
程序改进
只要程序客户端在发送完数据之后告诉服务端我再也不发送数据了,那么服务端就不会继续阻塞等待了,所以解决办法就是,先发送数据的一方调用socket.shutdownOutput();,这样的话,服务端在接受完数据之后就不会继续阻塞等待客户端发送数据了,这样程序就能够正常的执行下去
客户端
public class MyTcpClient {
public static void main(String[] args) throws IOException {
try(Socket socket = new Socket("localhost", 6666);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
){
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello!");
bufferedWriter.newLine();
bufferedWriter.write("r u ok?");
bufferedWriter.newLine();
bufferedWriter.flush();
socket.shutdownOutput();//// 关闭输出流,通知服务端,写出数据完毕
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String str= null;
while ((str = reader.readLine())!=null){
System.out.println(str);
}
}
}
}
服务端
public class MyTcpServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(6666);
while (true){
Socket clientSocket = server.accept();
System.out.println(clientSocket);
new Thread(()->{
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()
) {
deal(inputStream,outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
private static void deal(InputStream inputStream, OutputStream outputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
String str = null;
while ((str = reader.readLine())!=null){
System.out.println(str);
}
writer.write("收到!");
writer.newLine();
writer.flush();
System.out.println("deal finish!");
}
}
TCP文件传输
客户端
public class MyTcpFileClient {
public static void main(String[] args) throws IOException {
try(Socket socket = new Socket("127.0.0.1",9000);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./src/kehao/net/tcp/gakki.jpg"))){
byte[] bytes = new byte[1024];
int len=0;
while ((len = bis.read(bytes))!=-1){
os.write(bytes,0,len);
}
os.flush();
System.out.println("发送完成");
socket.shutdownOutput();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String str = null;
while ((str = reader.readLine())!=null){
System.out.println(str);
}
}
}
}
服务端
public class MyTcpFileServere {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9000);
while (true){
Socket socket = serverSocket.accept();
new Thread(()->{
try (InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream()
){
deal(is,os);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
private static void deal(InputStream is, OutputStream os) throws IOException {
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src/kehao/net/tcp/download/"+System.currentTimeMillis()+"gakki.jpg"))){
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.flush();
}
System.out.println("写入完成");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write("已经收到!");
writer.newLine();
writer.flush();
}
}

浙公网安备 33010602011771号