Socket编程
一、单线程TCP编程
1、Server端实现
package com.study.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args){
<font color=red>//1、建立ServerSocket的对象,并设定端口号(这里以本机为服务器)</font>
try {
<font color=red>//系统中0-1023是默认分配的,所以最好还是使用1023之后的port</font>
ServerSocket serverSocket=new ServerSocket(8888);
System.out.println("Server启动,等待客户端中。。。");
<font color=red>//2、使用accept方法阻塞式的监听客户端的发来的信息</font>
Socket socket = serverSocket.accept();
<font color=red>//3、获得读取流,获得从客户端的数据</font>
InputStream is=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String msg=null;
while((msg=br.readLine())!=null){
System.out.println("Server接受到从客户端的信息:"+msg);
}
OutputStream os = socket.getOutputStream();
PrintWriter pw=new PrintWriter(os);
pw.write("我是服务端,响应了客户端的Hello,你也Hello!");
<font color=red>//4、关闭相关资源</font>
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、客户端实现
// Java代码
package com.study.socket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
<font color=red>// 1、使用Socket监听服务器的端口号</font>
try {
Socket socket = new Socket("localhost", 8888);
<font color=red>// 2、使用输入流发送要给服务端的信息</font>
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("Hello,Server!");
pw.flush();// 在客户端,将数据刷新到流中
<font color=red>// 3、关闭相关资源</font>
socket.shutdownOutput();
InputStream is = socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String responseFormServer=null;
while((responseFormServer=br.readLine())!=null){
System.out.println("服务器端的响应为:"+responseFormServer);
}
br.close();
isr.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上便使用了socket实现了服务端和客户端之间的连接通讯
3、实现的基本思路
服务端
在服务端,我们只需要监听该主机的某个端口号port,并使用ServerSocket的accept方法进行阻塞式的接受;
在客户端,我们需要得知server的主机地址和数据报需要发送至的端口号,这样就行了
如果需要同时通讯,我们需要同时在服务端和客户端加上相应的代码和请求的代码即可。
二、多线程TCP编程
1、ServerThread实现
// Java代码
package com.study.socket.MultiThreadSocket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 这里的socket不能够关闭
* @author RadAsm
*
*/
public class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
super.run();
<font color=red>// 1、建立ServerSocket的对象,并设定端口号(这里以本机为服务器)</font>
try {
<font color=red>// 系统中0-1023是默认分配的,所以最好还是使用1023之后的port</font>
<font color=red>// 3、获得读取流,获得从客户端的数据</font>
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println("Server接受到从客户端的信息:" + msg);
}
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("我是服务端,响应了客户端的Hello,你也Hello!");
<font color=red>// 4、关闭相关资源</font>
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、Server端实现
// Java代码
package com.study.socket.MultiThreadSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
private static ArrayList clientLists=new ArrayList<String>();
public static void main(String[] args){
try {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server启动,等待客户端中。。。");
<font color=red>// 2、使用accept方法阻塞式的监听客户端的发来的信息</font>
Socket socket=null;
while(true){
socket = serverSocket.accept();
String hostAddress = socket.getInetAddress().getHostAddress();
<font color=red>if(!clientLists.contains(hostAddress)){
clientLists.add(hostAddress);
}</font>
System.out.println("共有"+clientLists.size()+"个客户端正在访问我!");
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
基本思路
在服务端,我们需要每次在eccept方法建立的时候,创建一个serverThread的线程和不同的客户端进行交互;在客户端,要保证连接服务器的主机地址和端口号的正确性。
三、单线程UDP编程
1、server端的实现
// Java代码
package com.study.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServer {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket(8888);
System.out.println("服务端启动了。。。等待接收从客户端发来的消息。。。");
<font color=red>// 2、定义一个DataGramPacket,用于接受客户端发来的信息</font>
byte[] buf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
datagramSocket.receive(datagramPacket);
<font color=red>// 3、显示</font>
System.out.println("接收到了从客户端的消息,内容是"
+ new String(datagramPacket.getData()));
} catch (Exception e) {
e.printStackTrace();
} finally {
<font color=red>// 4、关系相关的资源</font>
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
使用UDP实现的服务端,我们使用DatagramSocket的对象去接受从客户端发送的DatagramPacket对象代表的用户数据报文,并使用一个字节数组去接收
2、client端的实现
// Java代码
package com.study.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP面向无连接,所以我们只需要在发送数据报的时候获取到服务器的地址和药发送的port即可
*
* @author RadAsm
*
*/
public class UDPClient {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
<font color=red>// 获得服务端的信息</font>
InetAddress serverAddress = InetAddress.getByName("localhost");
byte[] buf = "Hello,Server!".getBytes();
int port = 8888;
<font color=red>// 在客户端构造一个指向了服务端的某个端口的数据报</font>
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length,
serverAddress, port);
<font color=red>// 构造DataGramSocket去发送消息。</font>
datagramSocket = new DatagramSocket();
datagramSocket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
} finally {
<font color=red>// 4、关闭相关的资源</font>
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
在客户端,因为是不需要连接的UDP协议,因为我们提前获知了server的主机名称(getByName),这样,再使用DataGramPacket的 new DatagramPacket(buf, buf.length,serverAddress, port)方法去构建出需要向主机发送的数据报文,并直接发送给主机。注意,这里的server仍旧是阻塞式的接收从客户端发来的数据报。
四、多线程UDP编程
1、serverThread线程的实现
// Java代码
package com.study.multi_thread;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServerThread extends Thread {
private DatagramSocket socket;
public UDPServerThread(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
super.run();
try {
byte[] buf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
socket.receive(datagramPacket);
getInfoFromClient(datagramPacket);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(socket!=null){
socket.close();
}
}
}
<font color=red>server从客户端接收到数据后的显示</font>
protected void getInfoFromClient(DatagramPacket packet) {
}
}
2、server端的实现
// Java代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPServer{
public static void main(String[] args) {
try {
DatagramSocket datagramSocket=new DatagramSocket(8889);
UDPServerThread serThread=new UDPServerThread(datagramSocket) {
@Override
protected void getInfoFromClient(DatagramPacket packet) {
System.out.println(new String(packet.getData()));
}
};
serThread.start();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
3、client端的实现
// Java代码
package com.study.multi_thread;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* <font color=red>UDP面向无连接,所以我们只需要在发送数据报的时候获取到服务器的地址和药发送的port即可</font>
*
* @author RadAsm
*
*/
public class UDPClient {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
// 获得服务端的信息
InetAddress serverAddress = InetAddress.getByName("localhost");
byte[] buf = "Hello,Server!".getBytes();
int port = 8889;
// 在客户端构造一个指向了服务端的某个端口的数据报
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length,
serverAddress, port);
// 构造DataGramSocket去发送消息。
datagramSocket = new DatagramSocket();
datagramSocket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4、关闭相关的资源
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}