Socket编程基础

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对等的通信。

你可能感兴趣的:(java技术)