一台主机有个IP地址(逻辑地址),MAC(物理地址)。用IP可以找到一台主机。
能交换数据的是进程,进程之间交换数据,不是计算机。
一个程序.exe,静态的概念,一个进程,在内存中,运行态的概念。
某些进程会占用固定的端口,进程与端口对应。
把一个端口和进程建立联系的叫做绑定。
FTP《=》端口21
进程间通讯是两个端口建立连接。
由于机器通讯,要有相同的语言,为保证数据正常交互,预先约定好协议。
网络体系架构,解决异构性问题采用的是分层方法--把复杂网络互联问题划分为若干较小的,单一的问题。
分层-〉人解决复杂网络问题的一般思路。
OSI :
对等层不允许直接通讯,严格单项依赖,上层依赖下层提供的服务,下层不依赖于上层工作。
对等层是虚拟连接。
网络层----〉IP协议(寻址)(路由)
传输层----〉TCP传输控制协议,UDP用户数据报协议
TCP有很大开销,三次握手,保证数据可靠传输,
UDP用于对实时性要求的应用。他是把大块数据分成小的数据报,只发数据报,数据报自己负责寻址,所以不一定路径一样,顺序可能乱。
数据封装的概念,下一层对上层数据按照自己的格式进行再次封装,封装就是在数据前面加上特定的协议头部信息。数据打包
上层向一层一次,就封装一次,到另外一层就是反向的,解封一次。
TCP/IP
应用层
传输层
网络层
网络接口
端口是一种抽象的软件结构,与协议相关。
TCP:23和UDP:23不相关。
IP+Port就是一个Socket,是一个对象的概念。就好像电话机,电话号码和分机号
Socket是传输层的。网络编程要注意在哪一个层次编程。
基于TCP,java.net.ServerSocket,服务器进程。构造函数一个端口号
Socket s = ServerSocket.accept(),阻塞方法,可以返回一个与联入的客户端Socket对应的Socket。
客户端:Socket s1 = new Socket("127.0.0.1",6666);
s和s1不同。
获得数据,s.getInputStream(),s.getOutputStream()
s.close(),关闭socket,会自动关闭流,至少这时流不再可用。
import java.io.*;
import java.net.*;
public class Server{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8000);
Socket s = ss.accept();
PrintWriter out = new PrintWriter(s.getInputStream());
out.println("Server started!");
out.flush();
s.close();
ss.close();
}
}
import java.io.*;
import java.net.*;
public class Client{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",8000);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = in.readline();
System.out.println(str);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readline();
}
}
以上是最简单的Server和Client。
以下是本人编的多人群聊的聊天室。
import java.io.*;
import java.net.*;
import java.util.*;
public class NewServer{
private ServerSocket ss;
private int port = 7777;//默认端口
private static int online = 0;//当前服务在线人数
private List threadList;//客户端连入Server后,启动过的线程的集合,以便管理,群发
final static PrintWriter sysout;//服务器本地输出,无用,直接System.out,没问题。
static{
sysout = new PrintWriter(System.out,true);
}
public NewServer(int port)
{
if(port!=0){//参数为0,采用默认端口
this.port = port;
}
try{
ss = new ServerSocket(this.port);//绑定
threadList = new ArrayList();
sysout.println("Start service on " + this.port);
while(true)//死循环,用于处理客户端的连入,并启动独立线程,与客户端交换信息
{
Transmit t = new Transmit(ss.accept());//阻塞住,直到有客户端连接
threadList.add(t);//将即将启动的线程,加入list
t.start();
}
}catch(Exception e)
{
e.printStackTrace();
}
}
/** *//**
*
* 私有成员内部类(便于访问外部类私有属性),如果改为顶级类没有问题,封装了服务器与客户端交换数据的独立线程操作。
*/
private class Transmit extends Thread{
private BufferedReader input;//带缓冲的字符流,作为输入流,从中读取发送到服务器的信息
private PrintWriter output;//带缓冲的字符流,作为输出流,输入字符
private String serverinfo = System.getProperty("os.name")+" "+System.getProperty("os.arch")+" "+System.getProperty("os.version");
private Socket client;//ss.accept()返回的socket
private boolean quit = false;//判断是否退出
public Transmit(Socket sock){
this.client = sock;
try{
this.input = new BufferedReader(new InputStreamReader(client.getInputStream(),"gb2312"));
this.output = new PrintWriter(client.getOutputStream(),true);//auto flush
output.println("Now,Server has " + (online) + " people online!");
output.println(serverinfo);
}catch(Exception ex){}
}
public void run(){
try{
while(!quit)
{
String line = input.readLine();
if(line == null) quit = true;
else{
sysout.println("[ "+new Date().toString()+"Receive word From : "+client.getInetAddress()+" ]: " + line);//本地输出,可以重定向到文件
if(line.trim().equalsIgnoreCase("EXIT"))
{
output.println("See you");
quit = true;
}
else
sendToOtherMsg(client.getInetAddress().toString(),line);//遍历threadlist,群发信息
}
}
online--;
}
catch(SocketException e)
{
if(e.getMessage().indexOf("Connection reset")!=-1)//客户端退出
{
sysout.println(client.getInetAddress() + "offline");
online--;
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{
client.close();//socket会关闭所打开的流,不要强行关闭流,会有问题。
}catch(Exception e){}
}
}
//发送信息给其他线程所通讯的客户端
private void sendToOtherMsg(String ip,String msg)
{
Iterator it = threadList.iterator();
while(it.hasNext())
{
Transmit t = ((Transmit)it.next());
if(!t.isAlive()) //如果线程已经进入死亡状态,也就是线程已经运行完毕,remove掉
{
it.remove();
continue;
}
t.sendIt("["+ip+"]: "+msg);
}
}
private void sendIt(String msg)
{
output.println(msg);
}
}
public static void main(String[] args)
{
new NewServer(61248);
}
} 客户端:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ChatRoomClient{
private JTextArea jta;
private JTextField jtf;
private JFrame f;
private Socket conn;
private BufferedReader echo;
private PrintWriter pw;
private boolean done = false;
public ChatRoomClient(String host,int port){
creatGUI();
try{
conn = new Socket();
conn.connect(new InetSocketAddress(host,port),10000);//Socket连接
//通过桥转换,将socket得到的字节输入流按照gb2312编码方式转换为字符输入流,再封装为带缓冲的过滤流
echo = new BufferedReader(new InputStreamReader(conn.getInputStream(),"gb2312"));
//直接使用PrintWriter这个过滤流封装字节输出流为字符流,并带有缓冲,比BufferedWriter方法更多。
pw = new PrintWriter(conn.getOutputStream(),true);//auto flush
jta.append("Connected to " + conn.getInetAddress() + ":" + conn.getPort() + "\n");
while(!done){
String info = echo.readLine();
jta.append(info+"\n");
}
jta.append("client will be closed in 2s.\n");
Thread.sleep(2000);
System.exit(0);
}
catch(SocketException ex)
{
if(ex.getMessage().indexOf("Connection reset")!=-1)//服务器关闭
jta.append("Server down!\n");
if(ex.getMessage().indexOf("Connection refused: connect")!=-1)//服务器不通
jta.append("connection refused!\nplease check network!\n");
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
try{
conn.close();//只关闭socket
}catch(Exception ex)
{
}
}
}
private void creatGUI()
{
jta=new JTextArea();
jta.setEditable(false);
jtf=new JTextField();
f=new JFrame("Chat Client");
JScrollPane jp=new JScrollPane(jta);//构建带滑动条的JTextField
f.getContentPane().add(jp);
f.getContentPane().add(jtf,"South");//JDK 1.5取消getContentPane,直接add没问题
f.setSize(600,400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//右上角的叉子,生效,关闭窗体
f.setVisible(true);//设置可见,否则不可见
jtf.addActionListener(new ActionListener(){//添加事件处理
public void actionPerformed(ActionEvent e){
String s=jtf.getText();
if(s.trim().equalsIgnoreCase("EXIT"))
done = true;//让主线程的while退出,进而结束Client
pw.println(s);//利用输出流,输出到服务器信息。
jtf.setText("");
}
});
}
public static void main(String[] args){
ChatRoomClient c=new ChatRoomClient("127.0.0.1",7777);
}
}
UDP编程
编写一个时间服务器,客户端就向服务器索取一个时间。
import java.io.*;
import java.net.*;
import java.util.*;
public class Server{
static byte[] getTime(){
Date d= new Date();
return d.toString().getBytes();
}
public static void main(String[] args) throws Exception
{
DatagramPacket inDataPacket = null;
DatagramPacket outDataPacket = null;
byte[] msg= new byte[100];
byte[] time;
InetAddress clientAddress;
int clientPort;
DatagramSocket datagramSocket = new DatagramSocket(13);
System.out.println("UDP server active on port 13");
while(true) {
inDataPacket = new DatagramPacket(msg, msg.length);
// Get the message.
datagramSocket.receive(inDataPacket);
String s=new String(inDataPacket.getData());
System.out.println(s);
//============================================================
// Retrieve return address information, including InetAddress
// and port from the datagram packet just recieved.
clientAddress = inDataPacket.getAddress();
clientPort = inDataPacket.getPort();
// Get the current time.
time = getTime();
//set up a datagram to be sent to the client using the
//current time, the client address and port
outDataPacket = new DatagramPacket(time, time.length, clientAddress, clientPort);
//finally send the packet
datagramSocket.send(outDataPacket);
}
}
} UDP的端口与TCP上的端口没关系,端口和协议有关。
import java.io.*;
import java.net.*;
public class Client{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();
String s = "Hello World";
DatagramPacket outDataPacket = new DatagramPacket(s.getBytes(),s.length(),InetAddress.getLocalHost(),13);
ds.send(outDataPacket);
byte[] msg = new byte[100];
String receivedMsg;
DatagramPacket inDataPacket = new DatagramPacket(msg, msg.length);
ds.receive(inDataPacket);
receivedMsg = new String(inDataPacket.getData(), 0, inDataPacket.getLength());
System.out.println(receivedMsg);
//close the socket
ds.close();
}
} 服务器需要客户端先向服务器发送一个信息,服务器才能提供服务。再回复信息,因为UDP面向非连接的。
Socket之间交换数据。
交换DatagramPacket,内容在字节数据中,发送方在Pocket写上地址和端口,send。
接收方必须准备一个空信,以便接收内容。received,将字节数组装满。
=========================================
URL编程
import java.io.*;
import java.net.*;
import java.util.*;
public class URLConnectionTest {
public static void main(String[] args) {
try {
String urlName;
if (args.length > 0) urlName = args[0];
else urlName = "http://www.tarena.com.cn";
//step 1. Create a URL
URL url = new URL(urlName);
URLConnection con = url.openConnection();
//step 2. Connect to the server
con.connect();
// print header fields
int n = 1;
String key;
while ((key = con.getHeaderFieldKey(n)) != null) {
String value = con.getHeaderField(n);
System.out.println(key + " = " + value);
n++;
}
// print convenience functions
System.out.println();
System.out.println("getContentType: " + con.getContentType());
System.out.println("getContentLength: " + con.getContentLength());
System.out.println("getContentEncoding: " + con.getContentEncoding());
System.out.println("getDate: " + con.getDate());
System.out.println("getExpiration: " + con.getExpiration());
System.out.println("getLastModifed: " + con.getLastModified());
System.out.println();
//step 3 and 4. Get an InputStream and encapsulate it
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
// print first ten lines of contents
String line;
n = 1;
//step 5. Read info from the stream
while ((line = in.readLine()) != null && n <= 100) {
System.out.println(line);
n++;
}
if (line != null) System.out.println(". . .");
}
catch (IOException exception) {
exception.printStackTrace();
}
}
}
posted on 2005-12-29 14:19
北国狼人的BloG 阅读(376)
评论(1) 编辑 收藏