1.java传统的TCP socket编程是阻塞方式,一个简单的Socket程序例子如下:
(1).服务端程序:
import java.io.*;
import java.net.*;
public class SocketServer{
public static final int PORT = 10500;
public static void main(String[] args)throws IOException{
//本机测试程序,无需指定ip地址
ServerSocket server = new ServerSocket(PORT);
System.out.println(“Started:” + server);
try{
//阻塞直到客户端连接
Socket socket = s.accept();
try{
System.out.println(“Connection accepted:” + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//自动刷新的PrintWriter
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
while(true){
String str = in.readLine();
if(str.equals(“END”)) break;
System.out.println(“Echoing:” + str);
out.println(str);
}
}finally{
System.out.println(“closing…”);
socket.close();
}
}finally{
server.close();
}
}
}
(2).客户端程序:
import java.io.*;
import java.net.*;
public class SocketClient{
public static void main(String[] args)throw IOException{
//获取本机回环的127.0.0.1地址,还可以使用InetAddress.getByName(“localhost”)
//或InetAddress.getByName(“127.0.0.1”);
InetAddress addr = InetAddress.getByName(null);
System.out.println(“addr = ”+ addr);
Socket socket = new Socket(addr, SocketServer.PORT);
try{
System.out.println(“socket = ” + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//自动刷新的PrintWriter
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
for(int i = 0; i < 10; i++){
out.println(“howdy ” + i);
String str = in.readLine();
System.out.println(str);
}
out.println(“END”);
}finally{
System.out.println(“closing…”);
socket.close();
}
}
}
Socket连接必须有四个重要信息:服务端IP地址、服务端端口、客户端IP地址和客户端端口,这四个信息都具备了,服务端程序和客户端程序才能相互交互。例如客户端程序的端口为12000,则:
服务端打印的Socket信息为:
Socket[addr=127.0.0.1,port=10200,localport=10500]
其中addr和port为客户端的ip和端口,localport为服务端端口。
客户端打印的Socket信息为:
Socket[addr=localhost/127.0.0.1,port=8080, localport=12000]
其中addr和port为客户端连接的服务端ip和端口,localport为客户端端口。
2.多服务端多客户端的Socket程序:
1中的例子服务端只能为一个客户端程序服务,若要为多个客户端程序提供服务,就必须使用多线程方式处理客户端请求,例子如下:
(1).服务端程序:
import java.io.*;
import java.net.*;
class SocketServer extends Thread{
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServerSocket(Socket s)throws IOException{
socket = s;
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//自动刷新的PrintWriter
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
start();
}
//多线程处理与客户端交互
public void run(){
try{
while(true){
String str = in.readLine();
if(str.equals(“END”)) break;
System.out.println(“Echoing:” + str);
out.println(str);
}
System.out.println(“closing…”);
}catch(IOException e){
System.err.println(“IO Exception”);
}finally{
try{
socket.close();
} catch(IOException e){
System.err.println(“Socket not closed”);
}
}
}
}
public class MultiServer{
static final int PORT = 10500;
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(PORT);
System.out.println(“Server Started”);
try{
while(true){
Socket s = server.accept();
try{
//创建多线程处理与客户端交互操作
new SocketServer(s);
}catch(IOException e){
s.close();
}
}
}finally{
server.close();
}
}
}
(2).客户端程序:
import java.net.*;
import java.io.*;
class SocketClient extends Thread{
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public int getThreadCount(){
return threadcount;
}
public SocketClient(InetAddress addr){
System.out.println(“Creating client:” + id);
Threadcount++;
try{
socket = new Socket(addr, SocketServer.PORT);
}catch(IOException e){
System.err.println(“Create socket failed”);
}
try{
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//自动刷新的PrintWriter
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
start();
}catch(IOException e){
try{
socket.close();
}catch(IOException ex){
System.err.println(“Socket not closed”);
}
}
}
//多线程方式处理与服务端的交互
\public void run(){
try{
for(int i = 0; i < 25; i++){
out.println(“Client ” + id + “ :” + i);
String str = in.readLine();
System.out.println(str);
}
out.println(“END”);
}catch(IOException e){
System.err.println(“IO Exception”);
}finally{
try{
socket.close();
}catch(IOException e){
System.err.println(“Socket not closed”);
}
threadcount--;
}
}
}
public class MultiClient{
static final int MAX_THREADS = 40;
public static void main(String[] args)throws IOException, InterruptedException{
InetAddress addr = InetAddress.getByName(null);
while(true){
if(SocketClient. getThreadCount() < MAX_THREADS){
//创建一个Socket客户端线程
new SocketClient(addr);
Thread.currentThread().sleep(1000);
}
}
}
Socket客户端程序的端口由系统分配,在创建时只需要指定要连接的目标服务端端口即可。
3.UDP Socket编程小例子:
前面的两个例子是TCP的socket编程,对于可靠性要求不高,而对速度要求很高的情况,需要使用UDP,UDP的例子程序如下:
(1).服务端程序:
import java.net.*;
public class UDPServer{
private static final int SERVER_PORT = 5000;
private DatagramSocket dataSocket;
private DatagramPacket dataPacket;
private byte receiveByte[];
private String receiveStr;
public static void main(String[] args){
try{
dataSocket = new DatagramSocket(SERVER_PORT);
receiveByte = new byte[1024];
dataPacket = new DatagramPacket(receiveByte, receiveByte.length);
receiveStr = “”;
int i = 0;
while(i == 0){
//接收客户端发送的数据
dataSocket.receive(dataPacket);
i = dataPacket.getLength();
if(i > 0){
receiveStr = new String(receiveByte, 0, dataPacket.getLength());
System.out.println(receiveStr);
//循环接收数据
i = 0;
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
(2).客户端程序:
import java.io.*;
import java.net.*;
public class UDPClient{
private static final int CLIENT_PORT = 5001;
private DatagramSocket dataSocket;
private DatagramPacket dataPacket;
private byte sendDataByte[];
private String sendStr;
public static void main(String[] args){
try{
dataSocket = new DatagramSocket(CLIENT_PORT);
sendDataByte = new byte[1024];
sendStr = “UDP方式数据测试”;
sendDataByte = sendStr.getBytes();
//注意:端口是要发送的目标服务端端口
dataPacket = new DatagramPacket(sendDataByte, sendDataByte.length,
InetAddress.getByName(“localhost”), UDPServer.SERVER_PORT);
dataSocket.send(dataPacket);
}catch(SocketExcption se){
se.printStackTrace();
} catch(IOExcption ie){
ie.printStackTrace();
}
}
}
DatagramSocket是用于发送和接收UDP数据包的套接字,DatagramPacket是用于表示UDP的数据包。UDP通信中不存在严格意义上的服务端和客户端,每个程序既可以是服务端,又可以同时是客户端,可以实现P2P对等的通信。