网络编程TCP通信
背景知识
TCP 是面向连接的可靠的字节流的传输。TCP 通信模型是典型的客户机-服务器模型。
通信双方的通信模型如下:
- TCP 通信的双方使用 Socket 进行通信。
- 通信一方的 IP 地址及其端口号,合称为一个Socket,通信双方各自的 Socket,唯一地标识了本次双方的通信。
- Socket 中的 IP 地址唯一标识了一台主机,而端口号则唯一标识了该通信主机上的一个程序(或进程)。
程序用到的一些类
InetAddress 类
方法摘录如下:(参见java jdk8官方文档)
boolean equals(Object obj)
Compares this object against the specified object.
byte[] getAddress()
Returns the raw IP address of this InetAddress object.
static InetAddress[] getAllByName(String host)
Given the name of a host, returns an array of its IP addresses, based on the configured name service on the system.
static InetAddress getByAddress(byte[] addr)
Returns an InetAddress object given the raw IP address .
static InetAddress getByAddress(String host, byte[] addr)
Creates an InetAddress based on the provided host name and IP address.
static InetAddress getByName(String host)
Determines the IP address of a host, given the host’s name.
String getCanonicalHostName()
Gets the fully qualified domain name for this IP address.
String getHostAddress()
Returns the IP address string in textual presentation.
String getHostName()
Gets the host name for this IP address.
static InetAddress getLocalHost()
Returns the address of the local host.
static InetAddress getLoopbackAddress()
Returns the loopback address.
int hashCode()
Returns a hashcode for this IP address.
boolean isAnyLocalAddress()
Utility routine to check if the InetAddress in a wildcard address.
boolean isLinkLocalAddress()
Utility routine to check if the InetAddress is an link local address.
boolean isLoopbackAddress()
Utility routine to check if the InetAddress is a loopback address.
boolean isMCGlobal()
Utility routine to check if the multicast address has global scope.
boolean isMCLinkLocal()
Utility routine to check if the multicast address has link scope.
boolean isMCNodeLocal()
Utility routine to check if the multicast address has node scope.
boolean isMCOrgLocal()
Utility routine to check if the multicast address has organization scope.
boolean isMCSiteLocal()
Utility routine to check if the multicast address has site scope.
boolean isMulticastAddress()
Utility routine to check if the InetAddress is an IP multicast address.
boolean isReachable(int timeout)
Test whether that address is reachable.
boolean isReachable(NetworkInterface netif, int ttl, int timeout)
Test whether that address is reachable.
boolean isSiteLocalAddress()
Utility routine to check if the InetAddress is a site local address.
String toString()
Converts this IP address to a String.
ServerSocket 类(服务端)
构造器:
ServerSocket()
Creates an unbound server socket.
ServerSocket(int port)
Creates a server socket, bound to the specified port.
ServerSocket(int port, int backlog)
Creates a server socket and binds it to the specified local port number, with the
specified backlog.
ServerSocket(int port, int backlog, InetAddress bindAddr)
Create a server with the specified port, listen backlog, and local IP address to bind to.
我觉得比较常用的是这几个方法:
Socket accept()
Listens for a connection to be made to this socket and accepts it.
void bind(SocketAddress endpoint)
Binds the ServerSocket to a specific address (IP address and port number).
void bind(SocketAddress endpoint, int backlog)
Binds the ServerSocket to a specific address (IP address and port number).
void close()
Closes this socket.
Socker 类(客户端)
构造器有很多种形式,方法也是。。。
太长了我就不贴了,有需要的直接去查文档也比在这翻文章快。。。
示例代码
功能说明
该代码模拟一个在控制台实现的简易多人聊天室。
使用说明
- 使用时先运行服务端线程,再运行客户端线程。
- 如需多人聊天,可将Client多复制粘贴几遍(改改名字),一个类代表一个聊天对象
责任声明
虽然代码是实验指导书上的 ,但我不是直接复制粘贴上去,而是看完一遍然后再打一遍,贴的是我自己打的版本。
要是发现有误,是我的问题。
老师写的代码质量可是杠杠滴!
代码本体
服务端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
//本案例中服务端无法直接发送消息给客户端,而是将一个客户端的消息发送给所有客户端
public class SimpleServer {
//限定群聊人数为100,保存所有客户端socket信息
public static Socket [] group=new Socket[100];
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(10002);
System.out.println("----服务端服务启动!----");
//记录当前用户数量,不能超过group数组长度上限
int cnt=0;
//循环接收用户消息
while(true){
//每接受一个用户请求,产生一个新的socket
Socket socket=ss.accept();
group[cnt]=socket;
cnt++;
System.out.println("----服务已连接!----");
new ServerThread(socket,group).start();
}
}
}
class ServerThread extends Thread{
Socket client;
Socket[] group;
int num;
BufferedReader br;
public ServerThread(Socket client,Socket[] group)throws Exception{
super();
this.client=client;
this.group=group;
br=new BufferedReader(new InputStreamReader(this.client.getInputStream()));
}
public void run(){
try{
String content=null;
while(true){
if((content=br.readLine())!=null){
//把消息发送至各客户端
for (int i = 0; i < group.length; i++) {
if(group[i]!=null&&client!=group[i]){
PrintWriter pw=new PrintWriter(group[i].getOutputStream(),true);
pw.println(content);
}
}
//在服务端控制台也显示该信息
System.out.println(content);
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
客户端
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception{
//创建连接到本机,端口号为10002的socket
Socket client=new Socket("127.0.0.1",10002);
//这里暂时使用命令行界面,有需要再换成GUI或前端
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("系统消息:请输入您的昵称:");
String name=br.readLine();
System.out.println("系统消息:欢迎 "+name+" 加入聊天室!");
new ClientThread(client,name).start();
InputStream is=client.getInputStream();
BufferedReader acceptMsg=new BufferedReader(new InputStreamReader(is));
while(true){
//循环接收消息,cpu会在main和clientThread线程之间来回切换
String msg=acceptMsg.readLine();
//将收到的信息显示在控制台上,后期可以修改为显示到其他地方
System.out.println(msg);
}
}
}
class ClientThread extends Thread{
Socket client;
String name;
public ClientThread(Socket client,String name){
this.client=client;
this.name=name;
}
public void run(){
try{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw=new PrintWriter(client.getOutputStream(),true);
while(true) {
String msg = br.readLine();
msg = name + ":" + msg;
pw.println(msg);
}
}catch(IOException e){
e.printStackTrace();
}
}
}
- 点赞
- 收藏
- 关注作者
评论(0)