TCP编程
需求:完成网络登录功能:
用户输入用户名和密码,服务器给出登录成功或登录失败的提示
分析:使用基于TCP协议的SOCKET网络编程实现
TCP协议基于请求-响应模式
在网络通信中,第一次主动发起通讯的程序被称作客户端Client程序
第一次通讯中等待连接的程序被称作服务器端Server程序
利用IO流实现数据的传输
TCP/IP通信连接的简单过程:
位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息,B计算机的TCP/IP软件接收该消息,并进行检查,查看是否有它知道的程序正在该端口上接收消息。如果有,他就将该消息交给这个程序。
要使程序有效地运行,就必须有一个客户端和一个服务器。
TCP编程详细步骤:
服务器:创建ServerSocket,在指定端口监听并处理请求
客户端:创建Socket,向服务器发送请求
服务器端:
1.创建ServerSocket(int port)对象
2.在Socket上监听客户端的连接请求
3.阻塞、等待连接的建立----建立连接
4.接收并处理请求信息----服务请求
5.将处理结果返回给客户端----服务相应
6.关闭流和Socket对象
客户端
1.创建Socket(String host,int port)对象
2.向服务器发送连接请求----建立连接
3.向服务器发送服务请求----服务请求
4.接收服务结果----服务响应
5.关闭流和Socket对象
类 ServerSocket
此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
服务器套接字一次可以与一个套接字连接,如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入列队中,然后从中取出一个套接字,与服务器新建的套接字连接起来,若请求连接数大于最大容纳数,则多出的连接请求被拒绝。列队的最大容纳数默认大小是50.
服务器套接字的实际工作由 SocketImpl 类的实例执行。应用程序可以更改创建套接字实现的套接字工厂来配置它自身,从而创建适合本地防火墙的套接字。
调用ServerSocket类的accept()方法,会返回一个和客户端Socket对象相连接的Socket对象。服务器端的Socket对象使用getOutputStream()方法获得的输出流,将指向客户端Socket对象使用getlnputStream()方法获得的那个输入流;同样,服务器端的Socket对象使用getlnputStream()方法获得的输入流,将指向客户端Socket对象使用getOutputStream()方法获得的那个输出流。也就是说,当服务器向输出流写入信息时,客户端通过相应的输入流就能读取,反之亦然。
类 Socket
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。
查看下面程序
Server
package com.sxt.tcp;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 熟悉流程
* 创建服务器
* 1、指定端口 使用ServerSocket创建服务器
* 2、阻塞式等待连接 accept
* 3、操作: 输入输出流操作
* 4、释放资源
*/
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket创建服务器
ServerSocket server =new ServerSocket(8888);
// 2、阻塞式等待连接 accept
Socket client =server.accept();
System.out.println("一个客户端建立了连接");
// 3、操作: 输入输出流操作
DataInputStream dis =new DataInputStream(client.getInputStream());
String data =dis.readUTF();
System.out.println(data);
// 4、释放资源
dis.close();
client.close();
server.close();
}
}
Client
package com.sxt.tcp;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 熟悉流程
* 创建客户端
* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口
* 2、操作: 输入输出流操作
* 3、释放资源
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
//1、建立连接: 使用Socket创建客户端 +服务的地址和端口
Socket client =new Socket("localhost",8888);
//2、操作: 输入输出流操作
DataOutputStream dos =new DataOutputStream(client.getOutputStream());
String data ="hello";
dos.writeUTF(data);
dos.flush();
//3、释放资源
dos.close();
client.close();
}
}
再看下面的程序
Client
package com.NetworkCommunication;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class TCPClient extends JFrame {
private PrintWriter printWriter;
Socket socket;
Container container;
private JTextArea jTextArea = new JTextArea(); //创建JTextArea()对象
private JTextField jTextField = new JTextField();//创建JTextField()对象
public TCPClient(String title){
super(title);//构造方法
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container = this.getContentPane(); //实例化对象
final JScrollPane jScrollPane = new JScrollPane();
jScrollPane.setBorder(new BevelBorder(BevelBorder.RAISED));
getContentPane().add(jScrollPane,BorderLayout.CENTER);
jScrollPane.setViewportView(jTextArea);
container.add(jTextField,"South");//将文本框放在窗体下面
jTextField.addActionListener(new ActionListener(){
//绑定事件
public void actionPerformed(ActionEvent e){
printWriter.println(jTextField.getText()); //将文本框中的信息写入流
jTextArea.append(jTextField.getText()+'\n');
jTextArea.setSelectionEnd(jTextArea.getText().length());
jTextField.setText(""); //将文本框清空
}
});
}
public void connect(){
jTextArea.append("尝试连接\n");
try {
socket = new Socket("localhost",8988);
printWriter= new PrintWriter(socket.getOutputStream(),true);
jTextArea.append("完成连接\n");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TCPClient tcpClient = new TCPClient("向服务器发送数据");
tcpClient.setSize(200,200);
tcpClient.setVisible(true);
tcpClient.connect();
}
}
Server
package com.NetworkCommunication;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
private BufferedReader bufferedReader;
private ServerSocket serverSocket;
Socket socket;
public void getServer(){
try {
serverSocket = new ServerSocket(8988);//实例化ServerSocket对象
System.out.println("服务器套接字已经创建成功");
while (true){
System.out.println("等待客户机的连接");
socket = serverSocket.accept(); //实例化Socket对象
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
getClientMessage();//调用getClientMessage()方法
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void getClientMessage(){
try {
while (true) { //如果套接字是连接状态
System.out.println("客户机:" + bufferedReader.readLine());//获得客户端信息
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bufferedReader != null) {
bufferedReader.close();//关闭流
}
if(socket!= null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TCPServer tcpServer = new TCPServer();
tcpServer.getServer();
}
}
TCP:单向通信Socket之服务器端
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 最简单的服务器端代码
* @author Administrator
*/
public class BasicSocketServer {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter bw = null;
try {
// 建立服务器端套接字:指定监听的接口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端建立监听");
// 监听,等待客户端请求,并愿意接收连接
socket = serverSocket.accept();
// 获取socket的输出流,并使用缓冲流进行包装
bw = new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
// 向客户端发送反馈信息
bw.write("hhhh");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流及socket连接
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP:单向通信Socket之客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
/**
* 最简单的Socket客户端
* @author Administrator
*/
public class BasicSocketClient {
public static void main(String[] args) {
Socket socket = null;
BufferedReader br = null;
try {
/*
* 创建Scoket对象:指定要连接的服务器的IP和端口而不是自己机器的
* 端口。发送端口是随机的。
*/
socket = new Socket(InetAddress.getLocalHost(), 8888);
//获取scoket的输入流,并使用缓冲流进行包装
br = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
//接收服务器端发送的信息
System.out.println(br.readLine());
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流及socket连接
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP:双向通信Socket之服务器端
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args){
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
BufferedReader br = null;
try {
//创建服务器端套接字:指定监听端口
ServerSocket server = new ServerSocket(8888);
//监听客户端的连接
socket = server.accept();
//获取socket的输入输出流接收和发送信息
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
//接收客户端发送的信息
String str = in.readLine();
System.out.println("客户端说:" + str);
String str2 = "";
//如果客户端发送的是“end”则终止连接
if (str.equals("end")){
break;
}
//否则,发送反馈信息
str2 = br.readLine(); // 读到\n为止,因此一定要输入换行符!
out.write(str2 + "\n");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP:双向通信Socket之客户端
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) {
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
BufferedReader wt = null;
try {
//创建Socket对象,指定服务器端的IP与端口
socket = new Socket(InetAddress.getLocalHost(), 8888);
//获取scoket的输入输出流接收和发送信息
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
wt = new BufferedReader(new InputStreamReader(System.in));
while (true) {
//发送信息
String str = wt.readLine();
out.write(str + "\n");
out.flush();
//如果输入的信息为“end”则终止连接
if (str.equals("end")) {
break;
}
//否则,接收并输出服务器端信息
System.out.println("服务器端说:" + in.readLine());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (wt != null) {
try {
wt.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
上面代码存在的缺陷或注意点
运行时,要先启动服务器端,再启动客户端,才能得到正常的运行效果。但是,上面这个程序,必须按照安排好的顺序,服务器和客户端一问一答!不够灵活!!可以使用多线程实现更加灵活的双向通讯!!
服务器端:一个线程专门发送消息,一个线程专门接收消息。
客户端:一个线程专门发送消息,一个线程专门接收消息。
TCP:聊天室之客户端
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class ChatClient {
public static void main(String[] args) {
Socket socket = null;
BufferedReader in = null;
try {
socket = new Socket(InetAddress.getByName("127.0.1.1"), 8888);
// 创建向服务器端发送信息的线程,并启动
new ClientThread(socket).start();
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// main线程负责接收服务器发来的信息
while (true) {
System.out.println("服务器说:" + in.readLine());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 用于向服务器发送消息
*
* @author Administrator
*
*/
class ClientThread extends Thread {
Socket s;
BufferedWriter out;
BufferedReader wt;
public ClientThread(Socket s) {
this.s = s;
try {
out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
wt = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (true) {
String str = wt.readLine();
out.write(str + "\n");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (wt != null) {
wt.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
TCP:聊天室之服务器端
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatServer {
public static void main(String[] args) {
ServerSocket server = null;
Socket socket = null;
BufferedReader in = null;
try {
server = new ServerSocket(8888);
socket = server.accept();
//创建向客户端发送消息的线程,并启动
new ServerThread(socket).start();
// main线程负责读取客户端发来的信息
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String str = in.readLine();
System.out.println("客户端说:" + str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 专门向客户端发送消息的线程
*
* @author Administrator
*
*/
class ServerThread extends Thread {
Socket ss;
BufferedWriter out;
BufferedReader br;
public ServerThread(Socket ss) {
this.ss = ss;
try {
out = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
br = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (true) {
String str2 = br.readLine();
out.write(str2 + "\n");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(out != null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(br != null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}