在Java中,基于TCP协议实现的网络通信类有两个:Socket类和ServerSocket类,客户端使用的是Socket类,服务器端使用的是ServerSocket类。使用它们可以方便的完成信息的交互,客户端与服务器端的连接,由服务器端向客户端提供服务。
Socket类建立连接的过程是:首先在服务器端指定一个用来等待连接的端口创建一个ServerSocket实例,然后在客户端通过规定一个主机与端口号创建一个Socket实例,连接到服务器上。ServerSocket类的accept方法使服务器处于阻塞状态,等待用户请求。
Scoket通信程序基本过程(4个步骤):
(1).在客户端和服务器端创建Scoket/ServerSocket实例。
(2).打开连接到Socket的输入/输出流。
(3).利用输入/输出流和Socket。
(4)关闭Socket(I/O流是基于Socket管道的,当Socket关闭时,I/O流也随之关闭)。
Socket连接过程如下图所示:
1.建立Socke连接
主要实现代码:
服务端:
客户端:
2.在客户端和服务器端同时打开输入/输出流
Socket 提供方法getinputStream()和getOutputStream()来得到对应的输入/输出流,进行数据的读写操作,方法分别返回InputStream对象和OutpputStream对象。可以把它们封装在缓冲流中以提高程序的性能,主要代码如下所示:
3.关闭输入/输出流
在客户端和服务器端关闭Socket.
范例演示:
创建一个简单的聊天程序为例演示Socket编程,该程序分为客户端和服务器端。服务器端能够接收到多个连接,客户端可以连接服务器,发送信息给服务器端,服务器接受消息,转发给所有客户。
实现结果如下图所示:
实现代码:
服务器端代码:
server.java
Client.java
主要实现代码:
服务端:
try{
ServerSocket server = new ServerSocket(9000);//服务器端建立套接字服务
}
catch(IOException e){
//
}
Socket socket = null;
try{
socket = server.accept();//监听客户端连接
}
catch(IOException e){
//
}
客户端:
try{
Socket client = new Socket(host,9000);//客户端创建套接字
}
catch(IOException e){
//
}
2.在客户端和服务器端同时打开输入/输出流
Socket 提供方法getinputStream()和getOutputStream()来得到对应的输入/输出流,进行数据的读写操作,方法分别返回InputStream对象和OutpputStream对象。可以把它们封装在缓冲流中以提高程序的性能,主要代码如下所示:
//输入流
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
//输出流
InputStreamWriter isw = new InputStreamWriter(socket.getOutputStream());
InputStreamReader isr = new InputStreamReader(isw);
3.关闭输入/输出流
在客户端和服务器端关闭Socket.
范例演示:
创建一个简单的聊天程序为例演示Socket编程,该程序分为客户端和服务器端。服务器端能够接收到多个连接,客户端可以连接服务器,发送信息给服务器端,服务器接受消息,转发给所有客户。
实现结果如下图所示:
服务器端代码:
server.java
package com.venus.myscoket.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
public class Server {
public Server(int port) throws Exception {//构造函数,参数为端口号
//创建ServerSocket
ServerSocket server = new ServerSocket(port);
//不断接受客户信息
while(true){
//监听客户端的连接
Socket conn = server.accept();
//将服务器端的输入流封装到DataInputStream类中,该类支持与机器无关的编码方式
DataInputStream in = new DataInputStream(conn.getInputStream());
//读取用户信息
String who = in.readUTF();
System.out.println("Client+(Ip:"+conn.getInetAddress()+")"+who+"enter!"+"\n");
//每次监听就创建一个线程
ServerHander cn = new ServerHander(who,conn);
cn.start();
}
}
public static void main(String args[]) throws Exception{
new Server(9013);
}
}
class ServerHander extends Thread{
Socket socket = null;
DataInputStream in = null;
DataOutputStream out = null;
String who = null;
//保护所有的客户端对象
protected static Vector<ServerHander>clientlist = new Vector<ServerHander>();
public ServerHander(String name,Socket socket) throws IOException {
this.who = name;
this.socket = socket;
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
@Override
public void run() {
try {
clientlist.addElement(this);
sendallclient("weclome "+who+" entered");
//无限循环
while(true){
String msg = in.readUTF();
sendallclient(who+" : "+msg);
}
} catch (IOException e) {
System.out.println("client exit or error.");
}finally{
clientlist.removeElement(this);
sendallclient(who+"left !");
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Connection has been closed");
}
}
}
/**
* 给客户端传递信息的方法
* @param msg
*/
protected static void sendallclient(String msg){
synchronized (clientlist) {//对客户端的vector加锁
Enumeration<ServerHander> allclients = clientlist.elements();
//遍历访问每个客户端对象
while(allclients.hasMoreElements()){
ServerHander serh = (ServerHander)allclients.nextElement();
try {
serh.out.writeUTF(msg);//向客户端发送信息
serh.out.flush();//刷新输出流,保证内容输出
} catch (IOException e) {
// TODO Auto-generated catch block
serh.interrupt();//终端线程
}
}
}
}
}
客户端代码:
Client.java
package com.venus.myscoket.server;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public ServiceFrame sf;//客户端窗体
private Socket csocket;//Socket对象
private DataInputStream in;//输入流
private DataOutputStream out;//输出流
public static void main(String[] args){
String who="";
//获得输出流
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
//输出提示信息
System.out.print("please input your name,and then please Enter :");
try {
//读取登录名
who = in.readLine().trim();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//调用Client构造函数
new Client(who,"172.20.83.37",9013);
}
public Client(String who,String server,int port){
//创建客户端窗体
sf = new ServiceFrame("简单聊天");
//添加键盘监听事件
sf.sendFD.addKeyListener(new ActListener(this, sf));
sf.addWindowListener(new ExitListener(this));
try {
//创建Socket对象
csocket = new Socket(server ,port);
//输入流
in = new DataInputStream(new BufferedInputStream(csocket.getInputStream()));
//输出流
out = new DataOutputStream(new BufferedOutputStream(csocket.getOutputStream()));
//向输出流输出who信息
out.writeUTF(who);
//刷新输出流
out.flush();
while(true){
sf.showTA.append("--"+in.readUTF()+"\n");//在窗体输出信息
}
} catch (Exception e) {
System.out.println("Server error!");
this.close();
System.exit(0);
}
}
protected void send(String msg){//输出信息
try {
out.writeUTF(msg);
out.flush();
} catch (IOException e) {}
}
protected void close(){
try {
sf.dispose();
out.close();
in.close();
csocket.close();
} catch (IOException e) {}
}
}
class ServiceFrame extends Frame{
protected TextArea showTA;
protected TextField sendFD;
public ServiceFrame(String winnm){
super(winnm);
setLayout(new BorderLayout());
add("North",showTA = new TextArea());
showTA.setEditable(false);
add("South",sendFD = new TextField());
pack();
show();
sendFD.requestFocus();
}
}
class ActListener extends KeyAdapter{
Client client;
ServiceFrame sFrame;
public ActListener(Client c,ServiceFrame sf) {
client = c;
sFrame = sf;
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
client.send(sFrame.sendFD.getText());
sFrame.sendFD.setText("");
}
}
}
class ExitListener extends WindowAdapter{
Client client;
public ExitListener(Client c){
client = c;
}
public void windowClosing(WindowEvent e){
client.close();
System.exit(0);
}
}