`

9、socket

    博客分类:
  • java
 
阅读更多
“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容“
   TCP/IP只是一个协议栈,就像程序运行一样,必须要实现运行,同时还要提供对外的操作接口

网络从下往上分为
  物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层,
    应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。
  通过Socket,我们才能使用TCP/IP协议;实际上,Socket跟TCP/IP协议没有必然的联系。
  Socket编程接口在设计的时候,希望也能适应其他的网络协议。
  所以说,Socket的出现只是使得程序员方便地使用TCP/IP协议,是对TCP/IP协议的抽象,从而形成了一些基本的函数接口,比如create、listen、connect、accept、send、read和write等等。
  实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。
  一、什么是TCP连接的三次握手
  第一次握手:客户端发送syn包(synchronous 同步的; sɪŋkrənəs, syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
  第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
  握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
  理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
  服务器和客户端均可以主动发起断开TCP连接请求,断开过程需要经过“四次握手”,最终确定断开。
  二、利用Socket建立网络连接的步骤
  建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
  套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
  1、服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
  2、客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。
  为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
  3、连接确认:当服务器端套接字监听到/接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。
  而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
  三、HTTP链接的特点
  HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。
  HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
  四、TCP和UDP的区别
  1、TCP是面向链接的,虽然说网络的不安全不稳定特性决定了多少次握手都不能保证连接的可靠性,但TCP的三次握手在最低限度上(实际上也很大程度上保证了)保证了连接的可靠性;
  而UDP不是面向连接的,UDP传送数据前并不与接收方建立连接,接收方也不发送确认信号,发送端不知道数据是否会正确接收,也不重发,所以说UDP是无连接的、不可靠的一种数据传输协议。
  2、由1描述的特点,使得UDP的开销更小、数据传输速率更高,因为不必进行收发数据的确认,所以UDP的实时性更好。
  知道了TCP和UDP的区别,就不难理解为何采用TCP传输协议的MSN比采用UDP的QQ传输文件慢了,但并不能说QQ的通信是不安全的,
  因为程序员可以手动对UDP的数据收发进行验证,比如发送方对每个数据包进行编号然后由接收方进行验证。


1、服务器端获取客服端传来的数据:
直接在eclipse中新建一个Server类:
import java.io.*;  
import java.net.*;  
public class Server {    
public static void main(String args[]) throws IOException {      
      int port = 8899;    
      //定义一个ServerSocket监听在端口8899上    
      ServerSocket server = new ServerSocket(port);    
      //server尝试接收客户端Socket的连接请求,server的accept方法是阻塞式的    
      Socket socket = server.accept();    
      //读取客户端发过来的信息    
      Reader reader = new InputStreamReader(socket.getInputStream());    
      char chars[] = new char[64];    
      int len;    
      StringBuilder sb = new StringBuilder();    
      while ((len=reader.read(chars)) != -1) {    
         sb.append(new String(chars, 0, len));    
      }    
      System.out.println("from client: " + sb);    
      reader.close();    
      socket.close();    
      server.close();    
   }    
}  

阻塞式:当服务器socket接收到数据才往后执行,没有收到数据就暂停在当前程序位置等待数据。
可以先执行Server的主方法,执行后,查看端口:cmd-->netstat -ano 就会发现8899端口处于监听的状态。
根据进程pid查看该端口被那个应用占用:
C:\Users\Administrator>tasklist|findstr 4844
javaw.exe                     4844 Console                    1     14,992 K
说明Server类的主方法并没有执行完毕。
Client类:
import java.io.*;  
import java.net.*;  
public class Client{  
    public static void main(String args[]) throws Exception {    
          String host = "127.0.0.1";  //要连接的服务端IP地址    
          int port = 8899;   //要连接的服务端对应的监听端口    
          //与服务端建立连接    
          Socket client = new Socket(host, port);    
          //建立连接后就可以往服务端写数据了    
          Writer writer = new OutputStreamWriter(client.getOutputStream());    
          writer.write("Hello Server.");    
          writer.flush();//写完后要记得flush    
          writer.close();    
          client.close();    
       }    
}  

执行Client的主方法,控制台上打印:from client: Hello Server.
这时再去查看端口8899,发现端口已经被关闭,Server的主方法执行完毕。
若先执行Client主方法会是怎样?会出现Connection refused: connect
若将Client类中writer.flush();删掉会是怎样?此时还是能读取到from client: Hello Server.

2、客服端、服务器同时读写数据:
每次数据写入时 添加结束标记:"eof";发现端口8899开启过多可以先关闭eclipse或javaw.exe,确保每次运行Server之前8899端口是关闭的。
Server:
import java.io.*;  
import java.net.*;  
public class Server {    
    public static void main(String args[]) throws IOException {    
          int port = 8899;    
          ServerSocket server = new ServerSocket(port);    
          Socket socket = server.accept();    
          Reader reader = new InputStreamReader(socket.getInputStream());    
          char chars[] = new char[64];    
          int len;    
          StringBuilder sb = new StringBuilder();    
          String temp;    
          int index;    
          while ((len=reader.read(chars)) != -1) {    
             temp = new String(chars, 0, len);    
             if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收    
                sb.append(temp.substring(0, index));    
                break;    
             }    
             sb.append(temp);    
          }    
          System.out.println("from client: " + sb);    
          //读完后写一句    
          Writer writer = new OutputStreamWriter(socket.getOutputStream());    
          writer.write("Hello Client32.eof3232");   //出现eof表示输入结束  
          writer.flush();    
          writer.close();    
          reader.close();    
          socket.close();    
          server.close();    
       }    
}  

Client类:
import java.io.*;  
import java.net.*;  
public class Client{  
     public static void main(String args[]) throws Exception {    
         String host = "127.0.0.1";  //要连接的服务端IP地址    
         int port = 8899;   //要连接的服务端对应的监听端口    
         Socket client = new Socket(host, port);    
         Writer writer = new OutputStreamWriter(client.getOutputStream());    
          writer.write("Hello Server");    
          writer.write("eof");    
          writer.flush();    
          Reader reader = new InputStreamReader(client.getInputStream());    
          char chars[] = new char[64];    
          int len;    
          StringBuffer sb = new StringBuffer();    
          String temp;    
          int index;    
          while ((len=reader.read(chars)) != -1) {    
             temp = new String(chars, 0, len);    
             if ((index = temp.indexOf("eof")) != -1) {    
                sb.append(temp.substring(0, index));    
                break;    
             }    
             sb.append(new String(chars, 0, len));    
          }    
          System.out.println("from server: " + sb);    
          reader.close();    
          writer.close();    
          client.close();    
       }    
}  

还是先执行Server主方法再执行Client主方法:
点击Console按钮切换Server/Client的打印信息:
from server: Hello Client32.
from client: Hello Server

3、多个客户端链接同一个服务器端
这才是实际需要的,还是以"eof"为结束标记;这里没有关闭端口。
Server:每次ServerSocket接收到一个新的Socket连接请求后新建一个线程来跟当前Socket进行通信,实现并发处理与客户端Socket进行通信的情况。由于现在的Server是异步处理数据的,不必一次性将客户端传来的数据读完,可以使用BufferedReader这个类,每次读取一行数据。
import java.io.*;  
import java.net.*;  
public class Server {    
@SuppressWarnings("resource")  
public static void main(String args[]) throws IOException {    
     int port = 8899;    
     ServerSocket server = new ServerSocket(port);    
      while (true) {    
         Socket socket = server.accept();    
         new Thread(new Task(socket)).start();   //启动Runnable接口下类的run()方法;  
      }    
   }    
       
   /**  
    * 用来处理Socket请求的  
   */    
   static class Task implements Runnable {    
     
      private Socket socket;    
          
      public Task(Socket socket) {    
         this.socket = socket;    
      }    
          
      public void run() {    
         try {    
            handleSocket();    
         } catch (Exception e) {    
            e.printStackTrace();    
         }    
      }    
          
      /**  
       * 跟客户端Socket进行通信  
      * @throws Exception  
       */    
      private void handleSocket() throws Exception {    
         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));    
         StringBuilder sb = new StringBuilder();    
         String temp;    
         int index;    
         while ((temp=br.readLine()) != null) {    
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收    
             sb.append(temp.substring(0, index));    
                break;    
            }    
            sb.append(temp);    
         }    
         System.out.println("from client: " + sb);    
         //读完后写一句    
       Writer writer = new OutputStreamWriter(socket.getOutputStream());    
         writer.write("Hello Client.");    
         writer.write("eof");    
         writer.flush();    
         writer.close();    
         br.close();    
         socket.close();    
      }    
   }    
}    

可以用线程实例多个Client对象模拟并发访问Server,这里就不实现了(也可以创建2个Client类简单模拟下)。
import java.io.*;  
import java.net.*;  
public class Client{  
    public static void main(String args[]) throws Exception {    
         String host = "127.0.0.1";  //要连接的服务端IP地址    
         int port = 8899;   //要连接的服务端对应的监听端口    
         Socket client = new Socket(host, port);    
         Writer writer = new OutputStreamWriter(client.getOutputStream());    
          writer.write("Hello Server first\n");    
          writer.write("Hello Server second\n");    
          writer.write("eof\n");    
          writer.flush();    
         BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));    
          StringBuffer sb = new StringBuffer();    
          String temp;    
          int index;    
          while ((temp=br.readLine()) != null) {    
             if ((index = temp.indexOf("eof")) >0) {    
                sb.append(temp.substring(0, index));    
                break;    
             }    
             sb.append(temp);    
          }    
          System.out.println("from server: " + sb);    
          writer.close();    
          br.close();    
          client.close();    
       }    
}  

设置编码:BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); 
         Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");

设置阻塞超时中断连接(一般设置在客户端),Socket提供setSoTimeout()方法来设置接收数据的超时时间,单位是毫秒,抛出SocketTimeoutException。
在server中添加:
        Thread.sleep(5000);
       //  writer.flush(); 
Client:
import java.io.*;  
import java.net.*;  
public class Client{  
    public static void main(String args[]) throws Exception {    
         String host = "127.0.0.1";  //要连接的服务端IP地址    
         int port = 8899;   //要连接的服务端对应的监听端口    
         Socket client = new Socket(host, port);    
         Writer writer = new OutputStreamWriter(client.getOutputStream());    
          writer.write("Hello Server 我的\n");    
          writer.write("Hello Server second\n");    
          writer.write("eof\n");    
          writer.flush();    
         BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));    
          client.setSoTimeout(2000);    
          StringBuffer sb = new StringBuffer();    
          try{  
              String temp;    
              int index;    
              while ((temp=br.readLine()) != null) {    
                  if ((index = temp.indexOf("eof")) >0) {    
                      sb.append(temp.substring(0, index));    
                      break;    
                  }    
                  sb.append(temp);    
              }    
          }catch(SocketTimeoutException e){  
              System.out.println("数据读取超时。");    
          }  
          System.out.println("from server: " + sb);    
          writer.close();    
          br.close();    
          client.close();    
       }    
}  

客服端就会打印超时;
可能出现的异常 Address already in use: JVM_Bind
最好用netstat -ano查看后、决定是否关闭相应进程或修改端口。
一般解决办法:
1、修改程序端口
2、重启eclipse或javaw.exe

前节讲到是字符串的传递,这里是服务器与客户端之间对象的传递:
1、创建一个User对象要实现序列化接口:
public class User implements java.io.Serializable{  
    private String name;  
    private Integer age;  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public Integer getAge() {  
        return age;  
    }  
    public void setAge(Integer age) {  
        this.age = age;  
    }  
}  

2、编写Server类:
import java.io.*;  
import java.net.*;  
public class Server {    
public static void main(String args[]) throws IOException, ClassNotFoundException {      
      int port = 8899;    
      //定义一个ServerSocket监听在端口8899上    
      ServerSocket server = new ServerSocket(port);    
      //server尝试接收客户端Socket的连接请求,server的accept方法是阻塞式的    
      Socket socket = server.accept();    
      ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());  
      User u=(User)ois.readObject();  
      System.out.println("from client: " + u.getName() +"年龄:"+ u.getAge());    
      ois.close();    
      socket.close();    
      server.close();    
   }    
}  

3、编写客户端:
import java.io.*;  
import java.net.*;  
public class Client{  
    public static void main(String args[]) throws Exception {    
         String host = "127.0.0.1";  //要连接的服务端IP地址    
         int port = 8899;   //要连接的服务端对应的监听端口    
         Socket client = new Socket(host, port);   
         User u =new User();  
         u.setAge(14);  
         u.setName("skx");  
         ObjectOutputStream oos =new ObjectOutputStream(client.getOutputStream());  
         oos.writeObject(u);  
         oos.close();    
         client.close();    
       }    
}

运行得到:
from client: skx年龄:14

qq聊天器模拟
依照韩顺平 山寨qq
我这里在公司里实现是可以的,无数据库,登陆账号1-20,密码123456,不要注册和添加好友,以免造成些麻烦
里面的ip地址是192.168.0.65这是我办公室电脑的局域网地址,下载之后自行更改ip地址,若单机可以更改为127.0.0.1
可以将Qclient打包成jar文件,添加bat命令,发送给同事,他们只需要点击bat就可以实现联机。
jar -qqc.jar
下载地址及提取码
链接: http://pan.baidu.com/s/1bndDR8j 密码: ctxb
分享到:
评论

相关推荐

    VC++ 9 socket HTTP

    在VC++ 9版本中,开发者可以利用其内置的Winsock库进行网络编程,实现TCP/IP协议下的Socket通信。本文将深入探讨如何在VC++ 9中使用Socket进行HTTP请求。 首先,我们需要理解Socket的基本概念。Socket是一种网络...

    PB9实现的SOCKET通讯协议

    在本场景中,我们关注的是PB9中实现的SOCKET通讯协议。SOCKET通讯协议是网络编程中的基础组件,它允许应用程序通过网络进行数据传输。以下是关于PB9和SOCKET通讯协议的详细知识: 1. **PowerBuilder 9基础知识**: ...

    PB9+TCP/ip通讯服务利用winSocket的例子(简单,测试通过)

    标题 "PB9+TCP/ip通讯服务利用winSocket的例子(简单,测试通过)" 指的是一个使用PowerBuilder 9(PB9)编程语言,并结合Windows Socket API(通常称为winSocket)实现TCP/IP通信的示例项目。这个项目已经过测试并确认...

    SocketTool socket工具

    9. **API接口**:除了图形界面,SocketTool可能还提供API接口,方便开发者将其集成到其他应用程序中,进行更复杂的操作。 在实际应用中,SocketTool可以广泛应用于网络服务的测试、网络协议的分析、网络性能的评估...

    hpsocket_delphi.rar_Delphi HPSOCKET_HPSocket_ZA9_delphi hpsocke

    标题中的“hpsocket_delphi.rar_Delphi HPSOCKET_HPSocket_ZA9_delphi hpsocke”指的是一款基于Delphi开发的HPSocket SDK,这是一个网络通信库,特别适用于Delphi编程环境。HPSocket是高性能的跨平台网络通信组件集...

    socket test 测试工具

    9. **安全性检查**:检查Socket通信过程中的安全问题,例如数据加密、身份验证等。 在提供的文件名称列表"SocketTest3"中,我们可以推测这可能是一个Socket测试工具的第三个版本,或者包含一系列关于Socket测试的...

    socket客户端_socket_

    9. **实例分析**: 压缩包中的“socket客户端”很可能包含了一个实际的Socket客户端示例代码,可能使用了Python或其他编程语言。代码中可能展示了上述步骤的具体实现,包括建立连接、发送数据、接收数据和关闭连接...

    Android开发,Socket Client端和Socket Server端数据发送和接收

    9. **示例代码** - Server端示例: ```java ServerSocket serverSocket = new ServerSocket(12345); Socket socket = serverSocket.accept(); BufferedReader reader = new BufferedReader(new ...

    c++Socket通信框架

    9. **套接字选项** `setsockopt`和`getsockopt`函数允许我们设置或获取Socket的选项,如超时时间、重试次数等,以适应不同场景的需求。 10. **网络协议** HP-Socket框架可能支持多种网络协议,如TCP/IP、UDP等,...

    HP-Socket5.4.1

    9. **性能优化**:作为一个成熟的库,HP-Socket可能会包含一些性能优化措施,如多线程处理、缓冲区管理等,以提高大规模并发下的通信效率。 10. **文档和社区支持**:通常,这样的库会附带详细的文档,解释如何使用...

    c# socket 传输文件

    9. **安全性** - 如果需要在不安全的网络环境中传输文件,可以考虑使用SSL/TLS加密Socket,提供数据传输的安全性。 10. **示例代码** ```csharp // Server端简化示例 Socket serverSocket = new Socket(Address...

    VC++ DLL for Socket

    9. **SocketError.h**:错误处理头文件,包含了Socket通信过程中可能出现的错误码和对应的处理机制。 在实际的开发过程中,开发者需要在`Communicate.cpp`中实现Socket的初始化、连接、监听、发送和接收等功能,并...

    pb下利用socket进行网络传输

    在PowerBuilder(PB)环境中,Socket编程是一种常用的技术,用于实现应用程序间的网络通信。本篇将深入探讨如何在PowerBuilder中利用Socket进行网络传输,并详细解释相关API函数及其用法。 首先,Socket是网络编程...

    android 2.3以后的socket注意

    9. **关闭资源**: 在完成Socket通信后,务必关闭输入流、输出流以及Socket本身,以防止内存泄漏和资源浪费。 10. **安全性**: 对于敏感数据传输,应使用SSL/TLS加密的Socket(即SSLSocket)以保证通信安全。 ...

    SocketTest.rar

    9. **安全性考虑**: 使用Socket通信时,还需要关注网络安全问题,如数据加密、身份验证、防止DDoS攻击等。SSL/TLS协议可以用于提供安全的Socket连接。 10. **性能优化**: 考虑到网络延迟和带宽限制,开发者可能...

    python:socket传输大文件示例

    9. **安全性与优化**: - 在实际应用中,应考虑安全因素,如使用SSL/TLS加密数据传输,防止数据被窃取或篡改。 - 对于大文件传输,可以考虑分块传输,或者使用断点续传机制,提高传输效率和可靠性。 10. **客户端...

    C#Socket通信稳定完整版类库实例

    9. **心跳机制** 为了保持连接的活跃,通常会实施心跳机制,即定期发送小量数据以确认连接状态。 10. **Wodsoft.Net库** 压缩包中的`Wodsoft.Net`可能是提供了一套封装好的Socket通信类库,它可能包含了上述功能...

    好用的Tcp Socket调试工具

    9. **兼容性**:适应不同的操作系统,如Windows、Linux、Mac OS等,以及各种编程语言的Socket接口。 关于提供的文件"Socket调试TCPCOM.exe",这可能是上述描述中的调试工具的可执行文件。根据文件名猜测,它可能是...

    socket_test.zip_Linux下的socket_linux socket_linux socket server_l

    9. **例子中的socket_test.tar**: 这个文件很可能是包含Linux下socket服务器和客户端程序的源代码压缩文件。解压后,我们可以查看这些示例代码,学习如何在实际项目中应用上述概念。 10. **www.pudn.com.txt**: ...

    实验一_SOCKET编程实验

    **9. 遇到的问题与解决方案** 常见问题可能包括连接失败、数据传输错误等。检查网络连接、端口号是否冲突、Socket操作顺序是否正确等,是解决这些问题的关键。 **10. 实验总结** 通过这个实验,你将了解Socket...

Global site tag (gtag.js) - Google Analytics