TCP流套接字编程
目录
1.ServerSocket API
2.Socket API
3实例1:显示
3.1服务器
3.1.1步骤
3.1.2代码
3.2.客户端
3.2.1步骤
3.2.2代码
3.3多线程
3.4用线程池调用任务
4.翻译服务器
1.ServerSocket API
ServerSocket 是创建TCP服务端Socket的API。
方法签名 | 方法说明 |
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
ServerSocket 方法:
方法签名 | 方法说明 |
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端 Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
voidclose() | 关闭此套接字 |
2.Socket API
Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。Socket 构造方法:
方法签名 | 方法说明 |
Socket(String host, intport) | 创建一个客户端流套接字 Socket ,并与对应 IP 的主机上,对应端口的进程建立连接 |
Socket 方法
方法签名 | 方法说明 |
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
3实例1:显示
3.1服务器
3.1.1步骤
- 进行网络编程,第一步要准备好socket实例
- 启动服务器
- 由于Tcp有连接,要先建立连接
- accept相当于接电话,如果客户端没有建立连接,就会阻塞
- accept返回一个socket对象,成为clientSocket,后序和客户端沟通就是通过clientSocket完成
- serverSocket就接电话,业务交给clientSocket
- 由于Tcp有连接,要先建立连接
- 实现连接方法--接下来处理请求和响应
- 循环处理每个请求然后响应
- 读取请求
- 根据请求计算响应
- 把响应返回给客户端
- 要关闭
- 实现计算响应的方法
3.1.2代码
public class TcpEchoSever {
private ServerSocket serverSocket=null;
public TcpEchoSever(int port) throws IOException {
serverSocket=new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动");
Socket clientSocket=serverSocket.accept();
processConnect(clientSocket);
}
private void processConnect(Socket clientSocket) {
System.out.printf("[%s:%d] 客户端连接!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
try(InputStream inputStream=clientSocket.getInputStream()){
try(OutputStream outputStream= clientSocket.getOutputStream()){
Scanner scanner=new Scanner(inputStream);
while(true){
if(!scanner.hasNext()){
System.out.printf("[%s:%d] 客户端断开连接\n",clientSocket.getInetAddress(),
clientSocket.getPort());
break;
}
String request=scanner.next();
String response=process(request);
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.println(response);
printWriter.flush();
System.out.printf("[%s:%d] rep:%s, resp: %s\n",
clientSocket.getInetAddress(),clientSocket.getPort(),request,response);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoSever tcpEchoSever=new TcpEchoSever(9090);
tcpEchoSever.start();
}
}
3.2.客户端
3.2.1步骤
- 进行网络编程,第一步要准备好socket实例
- 启动客户端
- 从控制台读取字符串
- 根据读取的字符串,构造请求,把请求发个服务器
- 从服务器读取响应,并解析
- 把结果显示在控制台上
3.2.2代码
public class TcpEchoClient {
private Socket socket=null;
public TcpEchoClient(String ServerIP, int SeverPort) throws IOException {
socket=new Socket("127.0.0.1",9090);
}
public void start(){
System.out.println("服务器连接成功");
Scanner scanner=new Scanner(System.in);
try(InputStream inputStream=socket.getInputStream()) {
try(OutputStream outputStream=socket.getOutputStream()){
while(true){
System.out.println("->");
String request=scanner.next();
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush();
Scanner respScanner=new Scanner(inputStream);
String response=respScanner.next();
System.out.printf("req: %s,resp: %s\n",request,response);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3多线程
主线程循环调用accept,当客户端连接,让主线程创建新线程,由新线程负责对客户端若干请求,提供服务(新线程中while循环来处理请求),多线程是并发执行的(宏观上是同时执行),就是各自执行各自的,不会干扰(每个客户端要连接都要分配一个线程)
public void start() throws IOException {
System.out.println("服务器启动");
while(true){
Socket clientSocket=serverSocket.accept();
Thread t=new Thread(()->{
processConnection(clientSocket);
});
t.start();
}
}
3.4用线程池调用任务
public void start() throws IOException {
System.out.println("服务器启动");
ExecutorService pool=Executors.newCachedThreadPool();
while(true){
Socket clientSocket=serverSocket.accept();
pool.submit(new Runnable() {
@Override
public void run() {
processConnect(clientSocket);
}
});
}
}
4.翻译服务器
TcpDictServer继承TcpThreadPoolEchoServer,重写process方法
public class TcpDictServer extends TcpThreadPoolEchoServer{
private HashMap<String,String> dict=new HashMap<>();
public TcpDictServer(int port) throws IOException {
super(port);
//简单构造几个词
dict.put("cat","小猫");
dict.put("dog","小狗");
dict.put("pig","小猪");
}
@Override
public String process(String request) {
return dict.getOrDefault(request,"当前词无法翻译");
}
public static void main(String[] args) throws IOException {
TcpDictServer server=new TcpDictServer(9090);
server.start();
}
}