面向连接传输协议(TCP)
两台电脑在传输数据前,会先建立一个专属的连接,就如打电话一般,双方通话时,会占有一条专属的通讯连接,当有一方挂机后,此连接就会消失。面向连接的协议特点:
- 确认回应:设甲乙两台电脑,当甲传数据到乙时,会等乙送回确认后才会再去传下一笔数据。当一段时间没有收到乙的确认回复,甲会试着再传一次,如果传送多次都没有回应,就表示连接可能断了。
- 分组序号:面向连接协议在传送数据的时候会把数据分割成固定大小的分组(packet),然后在每个分组上加上序号。序号用来检查哪些分组收到,哪些封包重复等。
- 流量控制
TCP是属于可靠性传输。
非面向连接传输协议(UDP)
与面向连接协议相比较,使用非连接协议传输数据的电脑间并不会建立一条专属的连接,这样的连接不可靠,分组可能丢失,可能收到重复的分组,也可能出现后面的分组比前面的分组先收到的情形。UDP协议一般用于短距离的传输,或者大量传输且容许些许错误的场合,如视频会议等,或者multicasting或则broadcasting。
连接端口
一台电脑可能同时运行着多个Server,那么此时还需要一个端口来明确客户端到底想连此台电脑的哪个Server。就如电话的分机号码,先拨通总机,然后总机根据提供的分机号码转到该分机。
Socket
Socket是程序与网络间的一种接口, 通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络,请求大部分的网络应用都是点对点的(point-to-point),所谓点就是服务端和客户端所执行的程序。Socket是用来接收或传送分组的一个端点。
Java中基本的 服务器——客户端 模型
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
示例代码:
服务器端:
public class TCPEchoServer {
public static final int PORT = 7777;
public static final String ADDR = "127.0.0.1";
protected void handleReq(Socket clnt) throws IOException
{
System.out.println("Client connected from: " + clnt.getInetAddress());
System.out.println(clnt.isConnected()+ "~~~~" + clnt.isClosed());
BufferedInputStream dataIn = new BufferedInputStream(clnt.getInputStream());
byte[] b = new byte[64];
int len = dataIn.read(b);
String sendBack = new String(b, 0, len);
sendBack = sendBack.toUpperCase();
OutputStream dataOut = clnt.getOutputStream();
dataOut.write(sendBack.getBytes());
dataIn.close();
dataOut.close();
System.out.println(clnt.isConnected()+ "~~~~" + clnt.isClosed());
}
public void start()
{
try
{
ServerSocket srv = new ServerSocket( PORT, 0, InetAddress.getByName(ADDR) );
System.out.println("Echo server start at port: " + PORT);
while( true )
{
// 此方法阻塞,直至有socket的连接请求过来
Socket clnt = srv.accept();
handleReq(clnt);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new TCPEchoServer().start();
}
}
客户端:
public class TCPEchoClient {
JFrame mainFrame;
JPanel container;
JLabel reqLabel;
JLabel resLabel;
JTextField reqTfld;
JTextField resTfld;
JButton sendBtn;
private class SendEchoAction implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
String reqStr = reqTfld.getText();
sendEcho(reqStr);
}
}
public void initUI()
{
mainFrame = new JFrame("Echo client");
setCmpt();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
private void setCmpt()
{
reqLabel = new JLabel("Input String:");
resLabel = new JLabel("Server return String:");
reqTfld = new JTextField();
resTfld = new JTextField();
sendBtn = new JButton("Send");
sendBtn.addActionListener(new SendEchoAction());
container = new JPanel();
container.setLayout(new GridLayout(2, 3));
container.add(reqLabel);
container.add(reqTfld);
container.add(sendBtn);
container.add(resLabel);
container.add(resTfld);
mainFrame.setLayout(new FlowLayout(FlowLayout.CENTER));
mainFrame.add(container);
}
public void sendEcho(String echo)
{
Socket snd = null;
try
{
snd = new Socket(TCPEchoServer.ADDR, TCPEchoServer.PORT);
OutputStream out = snd.getOutputStream();
out.write(echo.getBytes());
InputStream in = snd.getInputStream();
byte[] b = new byte[1024];
int len = in.read(b);
String resEcho = new String(b, 0, len);
resTfld.setText(resEcho);
}
catch (Exception e1)
{
e1.printStackTrace();
resTfld.setText(e1.getMessage());
}
finally
{
if( snd != null )
{
try
{
snd.close();
}
catch (IOException e1)
{
}
}
}
}
public static void main(String[] args) {
TCPEchoClient client = new TCPEchoClient();
client.initUI();
}
}
运行客户端如下:
多线程服务器端模型
为服务器端增加多线程处理连接,因为Java基于TCP的实现具有阻塞特性,若多个Client连接进来却不能并发处理的话,这样效率很低。此处只需server做改动。
示例代码:
服务器端:
public class TCPEchoMultiThreadServer extends TCPEchoServer{
@Override
public void handleReq(Socket clnt) throws IOException
{
// 重写此方法,睡它一下,模拟处理延时
try
{
Thread.sleep(1500L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
super.handleReq(clnt);
}
@Override
public void start()
{
try
{
ServerSocket srv = new ServerSocket(PORT, 0, InetAddress.getByName(ADDR));
System.out.println("Echo multi-thread server start at port: " + PORT);
while( true )
{
final Socket clnt = srv.accept();
Thread thread = new Thread( new Runnable()
{
@Override
public void run()
{
try
{
handleReq(clnt);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
);
thread.start();
// 打印出线程名字,可以看出每次请求都会新建线程来处理
System.out.println(thread.getName());
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new TCPEchoMultiThreadServer().start();
}
}
广播服务器模型:
玩Dota, LoL,当中同组的消息列就是属于广播模型
示例代码:
Server 端:
public class TCPEchoBroadcastServcer{
public static final int PORT = 7777;
public static final String ADDR = "127.0.0.1";
public static final String LOGIN_CODE = "#login";
public static final String LOGOUT_CODE = "#logout";
public static final String REGISTER_NEED = "#yourID";
public static final String FORMAL_MSG = "#fMsg";
private Map<String, Socket> clntSocketList;
public void start()
{
try
{
ServerSocket ss = new ServerSocket( PORT, 0, InetAddress.getByName(ADDR) );
System.out.println("Echo multi-thread server start at port: " + PORT);
clntSocketList = new HashMap<String, Socket>();
while( true )
{
final Socket clnt = ss.accept();
Thread thread = new Thread(
new Runnable()
{
@Override
public void run()
{
try
{
handleReq(clnt);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
);
thread.start();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
protected void handleReq(Socket clnt) throws IOException
{
System.out.println("Client connected from: " + clnt.getInetAddress());
InputStream dataIn = clnt.getInputStream();
byte[] b = new byte[64];
int len = dataIn.read(b);
String req = new String(b, 0, len);
// 这里实现比较挫,用了几个静态常量去区分消息种类,
// FORMAL_MSG代表的是普通消息,LOGIN_CODEclient连进server端的消息
// LOGOUT_CODE是离开server端消息
if( req.indexOf(FORMAL_MSG) == -1 )
{
if( req.indexOf( "["+LOGIN_CODE+"]" ) == 0 )
{
String clntId = req.split(":")[1];
clntSocketList.put(clntId, clnt);
req = "New client login";
}
else if( req.indexOf( "["+LOGOUT_CODE+"]" ) == 0 )
{
String clntId = req.split(":")[1];
if( clntSocketList.containsKey(clntId) )
{
clntSocketList.get(clntId).close();
clntSocketList.remove(clntId);
}
req = "A client left";
}
}
else
{
//普通消息需要进行截取字符串,比较挫,但一时想不出好办法。。。
req = req.substring(req.indexOf(FORMAL_MSG)+FORMAL_MSG.length()+1, req.length());
}
_sendBroadcastMsg(req);
}
private synchronized void _sendBroadcastMsg( String msg ) throws IOException
{
for( String key: clntSocketList.keySet() )
{
Socket clnt = clntSocketList.get(key);
if( !clnt.isClosed() && clnt.isConnected() )
{
this._sendMsg(clnt, msg);
//out.close();
}
}
}
private void _sendMsg( Socket clnt, String msg ) throws IOException
{
OutputStream out = clnt.getOutputStream();
out.write(msg.getBytes());
}
public static void main(String[] args)
{
new TCPEchoBroadcastServcer().start();
}
}
Client端:
public class TCPEchoBroadcastClient {
private String id;
JFrame mainFrame;
JPanel container;
JPanel row1;
JPanel row2;
JLabel reqLabel;
JLabel resLabel;
JTextField reqTfld;
JTextArea resTArea;
JButton sendBtn;
Socket connSocket;
public TCPEchoBroadcastClient()
{
this.id = UUID.randomUUID().toString();
}
private class SendEchoAction implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
String reqStr = reqTfld.getText();
sendEcho(reqStr);
}
}
private class DisconnectAction extends WindowAdapter
{
@Override
public void windowClosing(WindowEvent e)
{
try
{
_leftServer();
}
catch (IOException e1) {}
super.windowClosing(e);
}
}
public void initUI()
{
mainFrame = new JFrame("Echo Broadcast client");
setCmpt();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.addWindowListener(new DisconnectAction());
//mainFrame.pack();
mainFrame.setSize(500, 400);
mainFrame.setResizable(false);
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
_connectServer();
}
private void setCmpt()
{
row1 = new JPanel();
reqLabel = new JLabel("Input String:");
resLabel = new JLabel("Server return String:");
reqTfld = new JTextField();
resTArea = new JTextArea();
resTArea.setEditable(false);
sendBtn = new JButton("Send");
sendBtn.addActionListener(new SendEchoAction());
container = new JPanel();
GridBagLayout layout = new GridBagLayout();
container.setLayout(layout);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.weightx = 1;
gbc.gridwidth = 1;
gbc.gridheight = 1;
layout.setConstraints(reqLabel, gbc);
container.add(reqLabel);
gbc.weightx = 1;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.ipadx = 220;
layout.setConstraints(reqTfld, gbc);
container.add(reqTfld);
gbc.weightx = 1;
gbc.gridwidth = 0;
gbc.gridheight = 1;
gbc.ipadx = 0;
layout.setConstraints(sendBtn, gbc);
container.add(sendBtn);
JPanel resLbPanel = new JPanel();
resLbPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
resLbPanel.add(resLabel);
gbc.gridwidth = 1;
gbc.gridheight = 1;
layout.setConstraints(resLbPanel, gbc);
container.add(resLbPanel);
JScrollPane resTaPanel = new JScrollPane(resTArea);
resTaPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
resTaPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
gbc.weighty = 1;
gbc.gridwidth = 0;
gbc.gridheight = 1;
layout.setConstraints(resTaPanel, gbc);
container.add(resTaPanel);
mainFrame.add(container);
}
private void _connectServer()
{
try
{
connSocket = new Socket(TCPEchoBroadcastServcer.ADDR, TCPEchoBroadcastServcer.PORT);
this._registerToServer();
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
while( true )
{
_listenToServer();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
);
thread.start();
}
catch (Exception e)
{
e.printStackTrace();
if( connSocket != null )
{
try
{
connSocket.close();
}
catch (IOException ie) {}
}
}
}
private void _registerToServer() throws IOException
{
OutputStream out = connSocket.getOutputStream();
String reqStr = "[" + TCPEchoBroadcastServcer.LOGIN_CODE + "]:" + this.id;
out.write(reqStr.getBytes());
out.flush();
}
private void _leftServer() throws IOException
{
Socket snd = new Socket(TCPEchoBroadcastServcer.ADDR, TCPEchoBroadcastServcer.PORT);
OutputStream out = snd.getOutputStream();
String reqStr = "[" + TCPEchoBroadcastServcer.LOGOUT_CODE + "]:" + this.id;
out.write(reqStr.getBytes());
out.flush();
snd.close();
}
private void _listenToServer() throws IOException
{
if( connSocket.isClosed() )
{
return;
}
String resStr = null;
InputStream in = connSocket.getInputStream();
byte[] b = new byte[64];
int len = in.read(b);
if( len != -1 )
{
resStr = new String(b, 0, len);
resTArea.append(resStr+"\n");
}
}
public void sendEcho(String echo)
{
Socket snd = null;
try
{
snd = new Socket(TCPEchoBroadcastServcer.ADDR, TCPEchoBroadcastServcer.PORT);
OutputStream out = snd.getOutputStream();
echo = TCPEchoBroadcastServcer.FORMAL_MSG + ":" + echo;
out.write(echo.getBytes());
out.flush();
}
catch (Exception e1)
{
e1.printStackTrace();
}
finally
{
if( snd != null )
{
try
{
snd.close();
}
catch (IOException e1){}
}
}
}
public static void main(String[] args)
{
TCPEchoBroadcastClient client = new TCPEchoBroadcastClient();
client.initUI();
}
}
UDP通讯方式
最后是基于UDP传输协议的一个demo,具体应用场景还不太清楚。。。
Server 端:
public class UDPEchoServer {
public static final int PORT = 7777;
public static final String ADDR = "127.0.0.1";
public static void main(String[] args) {
DatagramSocket srv = null;
try
{
byte[] buffer = new byte[1024];
srv = new DatagramSocket(PORT);
DatagramPacket packet = new DatagramPacket(buffer, 1024);
System.out.println("Server is ready, Waiting requset come...");
while( true )
{
srv.receive(packet);
InetAddress clntAddr = packet.getAddress();
int clntPort = packet.getPort();
System.out.println("A request package from: " + clntAddr + " # " + clntPort);
String str = new String(packet.getData());
String echo = str.toUpperCase();
DatagramPacket resPacket = new DatagramPacket(echo.getBytes(), echo.length(), clntAddr, clntPort);
srv.send(resPacket);
}
}
catch (Exception e)
{
if( srv != null )
{
srv.close();
}
}
}
}
客户端:
public class UDPEchoClient {
JFrame mainFrame;
JPanel container;
JLabel reqLabel;
JLabel resLabel;
JTextField reqTfld;
JTextField resTfld;
JButton sendBtn;
private class SendEchoAction implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
String reqStr = reqTfld.getText();
sendEcho(reqStr);
}
}
public void initUI()
{
mainFrame = new JFrame("Echo client");
setCmpt();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
private void setCmpt()
{
reqLabel = new JLabel("Input String:");
resLabel = new JLabel("Server return String:");
reqTfld = new JTextField();
resTfld = new JTextField();
sendBtn = new JButton("Send");
sendBtn.addActionListener(new SendEchoAction());
container = new JPanel();
container.setLayout(new GridLayout(2, 3));
container.add(reqLabel);
container.add(reqTfld);
container.add(sendBtn);
container.add(resLabel);
container.add(resTfld);
mainFrame.setLayout(new FlowLayout(FlowLayout.CENTER));
mainFrame.add(container);
}
public void sendEcho(String echo)
{
DatagramSocket clnt = null;
try
{
clnt = new DatagramSocket();
byte[] sndEcho = echo.getBytes();
InetAddress addr = InetAddress.getByName(UDPEchoServer.ADDR);
DatagramPacket packet = new DatagramPacket(sndEcho, sndEcho.length, addr, UDPEchoServer.PORT);
clnt.send(packet);
clnt.receive(packet);
byte[] resData = packet.getData();
resTfld.setText(new String(resData));
}
catch (Exception e)
{
clnt.close();
}
}
public static void main(String[] args)
{
UDPEchoClient client = new UDPEchoClient();
client.initUI();
}
}
- 大小: 11.2 KB
- 大小: 40.6 KB
分享到:
相关推荐
这些入门示例可以帮助你理解Socket通信的基本流程,为进一步深入学习Java网络编程打下坚实基础。记得实践是检验真理的唯一标准,动手编写和运行代码是学习的最佳方式。在实践中遇到问题,不要忘记查阅相关文档或寻求...
### Java Socket编程入门知识点详解 #### 一、Java Socket编程基础概述 1. **平台无关性**:Java语言的一个显著特点就是平台无关性,这意味着编写的Java程序可以在任何支持Java虚拟机(JVM)的平台上运行。这对于...
通过这个入门例子,初学者可以理解Java Socket编程的基本原理和操作步骤,为进一步的网络编程打下坚实的基础。实际开发中,还可以结合NIO(非阻塞I/O)或其他高级框架如Netty,提高网络通信的效率和灵活性。
在这个"java通信socket入门实例"中,我们将探讨如何使用Java的Socket API来建立连接、交换数据以及关闭连接。这个入门示例可能包括了客户端(Client)和服务器端(Server)两部分代码,帮助初学者理解Socket通信的...
在本示例中,我们将深入探讨如何使用Java Socket进行图片的传输,这对于理解网络编程和数据交换至关重要。"Java Socket传输图片源代码"这个主题涵盖了以下几个关键知识点: 1. **Java Socket基础**: - Socket是...
在这个"一个简单的java socket程序"中,我们将会探讨如何构建一个基础的服务器端(Server)和客户端(Client)模型,这对于初学者来说是一个很好的入门级教程。 首先,我们需要理解Socket的基本概念。Socket在Java...
在这个“java socket案例”中,我们将深入探讨Socket的基本概念,以及如何创建和使用Socket进行简单数据传输,非常适合初学者入门。 1. **Socket基本概念** - **Socket**:Socket在计算机网络中被称为套接字,它是...
"Java基础入门"这个压缩包提供了学习Java编程的基础资源,包括经典的入门书籍源码和JDK11的中文版API文档。 首先,让我们来了解一下Java API。API(Application Programming Interface)是一系列预先定义的函数,...
以下是一个简单的Socket程序示例: **服务器端代码:** ```java import java.io.*; import java.net.*; public class SimpleServer { public static void main(String[] args) throws IOException { ...
在"Java从入门到精通(项目案例版)"中,你可能会遇到使用JFrame、JButton、JLabel等组件创建窗口应用的示例,以及事件监听器的使用,例如ActionListener,用于处理用户的交互事件。 4. 网络编程: Java的Socket...
这个“socket入门Demo”应该包含了基本的Socket编程实例,旨在帮助初学者理解和掌握Socket通信的基本原理和操作步骤。 Socket在概念上可以理解为通信的端点,它提供了在网络中发送和接收数据的接口。在Java中,...
此外,压缩包中的"Java2入门经典"可能还包括实践项目、示例代码和练习题,以帮助你巩固所学知识并提升编程技能。学习过程中,建议结合实际案例进行实践,以加深理解和记忆。随着你对Java 2平台的深入理解和熟练运用...
《Java TCP/IP Socket编程(原书第2版)》基于TCP/IP Socket相关原理,对如何在Java中进行Socket...《Java TCP/IP Socket编程(原书第2版)》适合作为Java Socket编程的入门教程,也可供从事网络相关专业的技术人员参考。
6. **网络编程**:Java提供了Socket编程接口,使得开发网络应用程序成为可能。"sl"中的实例可能涉及TCP/IP连接、数据的发送和接收,展示了如何进行网络通信。 7. **数据库操作**:Java JDBC(Java Database ...
这个“webrtc初学者的入门示例应用”是为那些想要学习如何使用WebRTC构建跨平台通信系统的人准备的。通过这个项目,你将了解如何在Web、Android、iOS和Windows上实现视频和音频通信的基本流程。 1. **基本概念** -...
根据给定的信息,“Java...综上所述,“Java2入门经典5”应该会涵盖上述所有关键知识点,并通过详细的示例和实践帮助读者更好地理解和掌握Java 2编程语言的基础知识。对于初学者来说,这本书将是一个非常有价值的资源。
### Java入门笔记9_Socket详解 #### 一、Socket概念与分类 在计算机网络通信领域,Socket被广泛地应用于客户端与服务器之间的数据交互。Socket,即套接字,是网络编程中的基本概念,用于实现不同计算机系统之间的...
《Java从入门到精通》(第三版)是一本旨在帮助初学者和有一定基础的程序员深入理解Java编程语言的书籍。光盘实例作为该书的重要补充,提供了丰富的代码示例和实际应用,帮助读者巩固理论知识并提升实战技能。在这些...
总的来说,Java聊天程序是一个基础的网络编程示例,它涵盖了网络通信的核心概念,包括Socket的使用、数据的发送与接收,以及基本的多线程处理。通过学习和实践,你可以更好地理解Java在分布式系统中的应用。
SocketDemo 是一个专门为Java初学者设计的用于学习和理解Socket通信基础的实例项目。Socket编程是网络编程的重要组成部分,它提供了进程间通过网络进行通信的能力。在这个例子中,我们将深入探讨Socket编程的基本...