博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 套接字通信笔记(一)
阅读量:5973 次
发布时间:2019-06-19

本文共 9715 字,大约阅读时间需要 32 分钟。

  • 协议

    TCP(传输控制协议),UDP(用户数据包协议)为传输层重要的两大协议,向上为HTTP提供底层协议,向下为数据链路层封装底层接口,乃是通信重中之重。TCP是面向流传输的协议,在编程中形象化为Stream,如流水一般,读入读出。流的基本单位为byte。而UDP则为数据包协议,以数据包为单位。协议的细节不再赘述,本次提供两种协议的最基础套接字编程模型。

  • API

    服务端最基本的流程:新建套接字->绑定端口->开始监听....->建立连接->传输数据->关闭连接

    客户端最基本的流程:新建套接字->连接...->传输数据->关闭连接

#服务端#这是新建套接字的API 第一个参数ARPA Internet地址格式,第二个参数是使用流协议,第三个参数是指定协议,并未遇到应用场景 通常 传0int server_socketfd = socket(PF_INET,SOCK_STREAM,0)#这是绑定函数 绑定已申请的socket描述符到端口上,第二个参数是ip地址结构体指针,第三个是地址描述结构体的长度bind(server_socketfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)#接受连接函数 意味开始监听 第一个参数是服务器套接字 第二个参数返回的是客户端连接的地址 第三个是地址长度accept(server_socketfd, (struct sockaddr *)&remote_addr,&sin_size)#客户端#客户端连接函数 第一个参数是socket对象描述符,第二个是ip地址,第三个是ip地址的长度connect(client_fd,(struct sockaddr *)&remote_addr, sizeof(struct sockaddr))#io#发送函数 第一个是发送的套接字描述符 第二个是内容 第三个是发送长度 第四个是flags 一般0send(client_socketfd,"welcome to login\n",21,0)
#接收函数 接受client对象的数据到buf中,一次接受bufferSize个长度,最后一个参数是flags 和send对应 recv(client_socketfd, buf, bufferSize, 0)
  • 完整程序

    为了方便测试,我使用了C++和Java做一对交互程序,C++做服务器的时候就用Java做客户端,反之也有。

    Linux socket API存在头文件sys/socket.h中,并且期间使用多个头文件的函数,大概使用的头文件如下。

#include 
#include
#include
#include
#include
#include
#include

    TCP服务端Demo

#ifndef COMMUNICAITON_TCPSOCKET_H#define COMMUNICAITON_TCPSOCKET_H#include 
#include
#include
#include
#include
#include
#include
#endif //COMMUNICAITON_TCPSOCKET_Hvoid tcpServerStart();#include "TCPSocket.h"const int bufferSize = 1024;void tcpServerStart(){ printf("server socket start init...\n"); int server_socketfd;//服务器套接字 int client_socketfd;//客户端套接字 int port = 8000; struct sockaddr_in my_addr;//服务器网络地址结构 struct sockaddr_in remote_addr;//虚拟网络地址结构 socklen_t sin_size;//此处须运用长度定义类型 socketlen_t char buf[bufferSize];//数据缓冲区 long sendLen = 0;//发送接收长度 memset(&my_addr,0,sizeof(my_addr));//数据初始化 my_addr.sin_family=AF_INET;//设置为IP通信 my_addr.sin_addr.s_addr=INADDR_ANY;//服务器ip my_addr.sin_port=htons(port);//设置端口为8000 /*创建服务器端套接字--IPv4协议,TCP协议*/ if((server_socketfd = socket(PF_INET,SOCK_STREAM,0))<0){ perror("socket init error"); return ; } /*将套接字绑定到服务器的网络地址上*/ if(bind(server_socketfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0){ perror("bind socket error"); return; } printf("server socket start listen ,port:%d",port); /*监听连接请求--监听队列长度为5*/ listen(server_socketfd,5); sin_size = sizeof(struct sockaddr_in); /*等待客户端连接请求到达*/ client_socketfd=accept(server_socketfd, (struct sockaddr *)&remote_addr,&sin_size); if(client_socketfd < 0){ perror("listen error"); return; } printf("accept %s",inet_ntoa(remote_addr.sin_addr));//打印客户端ip地址 sendLen=send(client_socketfd,"welcome to login\n",21,0);//发送欢迎信息 if(sendLen <= 0){ perror("no send"); return; } while(sendLen=recv(client_socketfd, buf, bufferSize, 0)>0){ printf("accept msg==="); printf("%s/n",buf); } close(client_socketfd); close(server_socketfd);}

    UDP服务端Demo

#ifndef COMMUNICAITON_UDPSOCKET_H#define COMMUNICAITON_UDPSOCKET_H#include 
#include
#include
#include
#include
#include
#include
#endif //COMMUNICAITON_UDPSOCKET_Hvoid udpServerStart();
#include "UDPSocket.h"const int bufSize = 1024;void udpServerStart(){    printf("udp server init...\n");    int server_sockfd;    int len;    int port = 8000;    struct sockaddr_in my_addr;    struct sockaddr_in remote_addr;    socklen_t sin_size;//此处使用其自定义的socklen属性    char buf[bufSize];    memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零    my_addr.sin_family = AF_INET;    my_addr.sin_addr.s_addr = INADDR_ANY;    my_addr.sin_port = htons(port);    /*创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议*/    if((server_sockfd=socket(PF_INET,SOCK_DGRAM,0))<0){        perror("create socket error");        return;    }    /*将套接字绑定到服务器的网络地址上*/    if(bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0){        perror("bind socket error");        return;    }    sin_size = sizeof(struct sockaddr_in);    printf("waiting for package");    /*接收客户端的数据并将其发送给客户端--recvfrom是无连接的*/    if((len=recvfrom(server_sockfd,buf,bufSize,0,(struct sockaddr *)&remote_addr,&sin_size))<0){        perror("recv error");        return;    }    printf("received packet from %s:\n",inet_ntoa(remote_addr.sin_addr));    printf("contents: %s\n",buf);    close(server_sockfd);}

    其中有某些函数调用非socket API中,比如memset,inet_ntoa等。

    TCP客户端 Demo

#ifndef COMMUNICAITON_TCPCLIENT_H#define COMMUNICAITON_TCPCLIENT_H#include 
#include
#include
#include
#include
#include
#include
#endif //COMMUNICAITON_TCPCLIENT_Hvoid tcpClient();#include "TCPClient.h"const int bufSize = 1024;void tcpClient(){ int client_fd; int len; struct sockaddr_in remote_addr; char buf[bufSize]; memset(&remote_addr,0, sizeof(remote_addr)); remote_addr.sin_family=AF_INET; remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); remote_addr.sin_port=htons(8000); /*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/ if((client_fd=socket(PF_INET,SOCK_STREAM,0))<0){ perror("socket error"); return; } /*将套接字绑定到服务器的网络地址上*/ if(connect(client_fd,(struct sockaddr *)&remote_addr, sizeof(struct sockaddr))<0){ perror("connect error"); return; } printf("connected to server\n"); len=recv(client_fd,buf,bufSize,0); printf("get msg :%s",buf); close(client_fd);}

    UDP客户端 Demo

#ifndef COMMUNICAITON_UDPCLIENT_H#define COMMUNICAITON_UDPCLIENT_H#include 
#include
#include
#include
#include
#include
#include
#endif //COMMUNICAITON_UDPCLIENT_Hvoid udpClient();/* * 向本地(localhost) 8000端口发送一个数据包 */const int buffSize = 1024;void udpClient(){ int client_sockfd; int len ; struct sockaddr_in remote_addr; int sin_size; char buf[buffSize]; memset(&remote_addr,0, sizeof(remote_addr)); remote_addr.sin_family=AF_INET; remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); remote_addr.sin_port=htons(8000); /*创建客户端套接字--IPv4协议,面向无连接通信,UDP协议*/ if((client_sockfd=socket(PF_INET,SOCK_DGRAM,0))<0) { perror("socket not found"); return; } stpcpy(buf,"this is a C++ udp client"); printf("send msg :%s\n",buf); sin_size= sizeof(struct sockaddr_in); /*向服务器发送数据包*/ if((len=sendto(client_sockfd,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr)))<0){ perror("send error"); return; } close(client_sockfd);}

    用于对应的Java客户端/服务端(比较熟悉Java,用于测试)

public class TCPClient {    public void tcpConnectReacServerFirst(String addr,int port){        Socket socket = null;        try{            socket = new Socket(addr,port);            InputStream ins = socket.getInputStream();            OutputStream ous = socket.getOutputStream();            BufferedReader bufReader = new BufferedReader(new InputStreamReader(ins));            String msg = bufReader.readLine();            System.out.println("接到服务器信息:"+msg);            ous.write("hello server\n".getBytes());            ous.flush();            ins.close();            ous.close();        }catch (Exception e){            e.printStackTrace();        }finally {            if(socket != null){                if(socket.isClosed()){                    try{                        socket.close();                    }catch (Exception e){                        e.printStackTrace();;                    }                }            }        }    }}
public class UDPClient {    public void udpSender(String addr,int port){        byte[] msg = "this is udp sender\n".getBytes();        try{            //数据包            //数据包byte数组 数组长度 包目的ip地址 端口            DatagramPacket datagramPacket = new DatagramPacket(msg,msg.length,InetAddress.getByName(addr),port);            DatagramSocket socket = new DatagramSocket();            socket.send(datagramPacket);            if(!socket.isClosed()){                socket.close();            }        }catch (Exception e){            e.printStackTrace();        }    }}
public class TCPServer {    public void tcpServerStart(int port){        ServerSocket server = null;        final String welcome = "welcome to login,Java TCP server!\n";        try{            server = new ServerSocket(port);            Socket socket = server.accept();            OutputStream ous = socket.getOutputStream();            ous.write(welcome.getBytes());            ous.close();            socket.close();            server.close();        }catch (Exception e){            e.printStackTrace();        }    }}
public class UDPServer {    public void udpStartup(int port,int byteCount){        System.out.println("udp server start ,port:"+port);        try{            InetAddress inet = InetAddress.getLoopbackAddress();            DatagramSocket udp = new DatagramSocket(port);            byte[] buf = new byte[byteCount];            DatagramPacket packet = new DatagramPacket(buf,buf.length);            udp.receive(packet);            String getMsg = new String(buf,0,packet.getLength());            System.out.println("收到客户端 "+packet.getAddress().getHostAddress()+" 发来信息:"+getMsg);            udp.close();        }catch (Exception e){            e.printStackTrace();        }    }}
  • 体会

    C++在unix中形成了一种对对象的描述,或为句柄、或为fd,将其理解为Java中的socket对象类比一下,就容易理解了。而传入地址以及长度,应该是操作系统需要新建空间申请内存而用。总而言之,在传统通信程序中,socket的模型就是连接对象,其最大的应用就是如下

while(true){   socket = accept();   Thread handler = new Handler(socket);   handler.start();}

    为此基础上优化,就是添加线程池,或者加请求队列。这种模式逻辑明了,编码简单,是最容易理解的编程模型。

转载于:https://www.cnblogs.com/chentingk/p/8438973.html

你可能感兴趣的文章
HDOJ 1036 输入输出 水
查看>>
Java 安装后的检测是否安装成功
查看>>
设备及分辨率
查看>>
mybatis拦截器
查看>>
App重新启动
查看>>
矩阵乘法
查看>>
得到目标元素距离视口的距离以及元素自身的宽度与高度(用于浮层位置的动态改变)...
查看>>
安装和配置Tomcat
查看>>
实验三
查看>>
第一次实验总结
查看>>
openssh for windows
查看>>
PostgreSQL cheatSheet
查看>>
ASP.NET Core 2 学习笔记(三)中间件
查看>>
转:Mosquitto用户认证配置
查看>>
SpringBoot上传文件到本服务器 目录与jar包同级
查看>>
python开发_difflib字符串比较
查看>>
被解放的姜戈01 初试天涯
查看>>
三极管工作区在Spectre中的表示
查看>>
HT for Web的HTML5树组件延迟加载技术实现
查看>>
ASP.NET MVC 3 Razor Nested foreach with if statements
查看>>