2 下面我们来写一下 TCP网络编程(下面是我们需要注意的一些点)
1 第一个类:ServerSocket,其中的accept这样的方法和TCP有连接有着很大的关系,accept就相当于接电话这个操作
客户端准备先尝试连接,就是服务器的操作系统的这一层和用户端进行一些相关的流程,先把这个连接准备好,这是先用一个Serversocket的一个对象来进行的;等到用户调用accept方法的时候,并得到一个Socket的返回值,称为climentsocket,这时才是真的把这个请求连接拿到客户端代码中
2 对于accept的返回值对应Socket这个文件,是有一个close方法的,如果打开一个文件后,是要记得去关闭文件的,如果不关闭,就可能会造成文件资源泄漏的情况;一个socket文件写完之后本应是要关闭的,但是咱们前面写的UDP程序是不可以关闭的,当时的socket是有生命周期的,都是要跟随整个程序的,当客户端不在工作时,进程都没了,PCB也没了,文件描述符就更没有了
3 TCPsocket,是面向字节流的,当我们具体读写数据的时候,就和之前读写文件是类似的,也就是使用InputStream,和Outputstream
4 咱们的TCP服务器有一个listenSocket,但是会有多个clientsocket,可以说每一个客户端,每一个请求都对应一个climentSocket;如果这个客户端断开链接了,对应的clientSocket也就需要销毁了
5 咱们的读数据和写数据都是以InputStream,和OutputStream,通过climentSocket.getInputStream,和climentsocket.getOutputStream来进行关联;
但是具体读的时候Scanner 来进行具体的读,new Scanner(InputStreaam),这事就巧妙地读到了客户端的请求;
写的时候,直接利用Printstream new Printstream()构造方法里面直接写Outputstream,当调用println方法的时候,就默认写回到客户端了
6 在读的时候,要注意此时只写一个Socket文件,直接把服务器的端口号和IP地址,传入进去进行构造,就自动地和客户端进行了连接;此时还要有InputStreamSocket和OutstreamSocket;此时要把屏幕中读到的字符串想办法和Socket关联起来,按我的理解来说,发送数据直接依靠println,读取数据直接依靠scan.next即可 先启动服务器,再启动客户端
下面是客户端的代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
class Request{
int serverport=0;
String serverIp=null;
Socket socket=null;
public Request(String serverIp,int serverport)throws IOException {
this.serverIp=serverIp;
this.serverport=serverport;
this.socket=new Socket(serverIp,serverport);
//让Socket创建的同时,就与服务器建立了链接,相当于拨电话的操作
}
public void start()throws IOException {
//1从键盘上读取请求
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("请输入你的请求内容");
System.out.println("->");
String request = scan.next();
if (request.equals("goodbye")) {
System.out.println("即将退出客户端");
break;
}
try (InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
//2 把这个读取的内容发给服务器
PrintStream printStream=new PrintStream(outputStream);
printStream.println(request);
//在这里我们怀疑println不是把数据发送到服务器中了,而是放到缓冲区里面了,我们刷新一下缓冲区,强制进行发送
printStream.flush();
//3读取请求
Scanner scanreturn=new Scanner(inputStream);
String response=scanreturn.next();
//System.out.println(1);
//4 显示
String string=String.format("请求是 %s,回应是 %s",request,response);
System.out.println(string);
}catch(IOException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
Request request=new Request("127.0.0.1",9090);
request.start();
}
}
下面是服务端的代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
class Server
{
ServerSocket listensocket=null;
public Server(int port)throws IOException {
this.listensocket=new ServerSocket(port);
}
public void start()throws IOException
{
System.out.println("服务器即将启动");
//UDP的服务器进入主循环之后,就尝试用receive建立请求了,这是无连接的
//但是我们的TCP是有连接的,首先需要做的事,先建立起连接,相当于客户端的代码是货品,就要通过一条公路来把这些货发送过去
//当服务器运行的时候,是否有客户端来建立连接,不确定,如果客户端没有建立连接,accept就会进行阻塞等待,如果有连接,accept方法就会返回一个
//Socket对象,也就是说进一步的客户端和服务器的交互就交给ClimentSocket来干
//每一个服务器都对应一个climentSocket
Socket climentSocket=listensocket.accept();
//System.out.println(1);
processConnection(climentSocket);
}
public void processConnection(Socket climentSocket)throws IOException {
System.out.println("这个客户端对应的服务器已经启动");
String str = String.format("客户端地址是: %s,客户端的端口号是 %d",climentSocket.getInetAddress(),climentSocket.getPort());
System.out.println(str);
try (InputStream inputStream = climentSocket.getInputStream();
OutputStream outputStream = climentSocket.getOutputStream()) {
while (true) {
//1 读取请求并解析
Scanner scanner = new Scanner(inputStream);
if (!scanner.hasNext()) {
System.out.println("这个客户端对应的服务器已经完成工作");
str = String.format("客户端的IP地址是%s,服务器的端口号是%d", climentSocket.getInetAddress().toString(), climentSocket.getPort());
// System.out.println(str);
break;
}
//2 读取请求并解析
String request = scanner.next();
String response = process(request);
//3 把解析内容那个返回到客户端
PrintStream writer = new PrintStream(outputStream);
writer.println(response);
writer.flush();
//快点返回去,不让数据在缓冲区逗留
str = String.format("客户端的IP地址是%s,服务器的端口号是%d", climentSocket.getInetAddress().toString(), climentSocket.getPort());
//System.out.println(str);
}
}catch(IOException e)
{
e.printStackTrace();
}finally {
climentSocket.close();
}
}
public String process(String str1)
{
return str1;
}
public static void main(String[] args) throws IOException{
Server server=new Server(9090);
server.start();
}
}



