• 协议

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

  • API

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

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

#服务端
#这是新建套接字的API 第一个参数ARPA Internet地址格式,第二个参数是使用流协议,第三个参数是指定协议,并未遇到应用场景 通常 传0
int server_socketfd = socket(PF_INET,SOCK_STREAM,)
#这是绑定函数 绑定已申请的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 一般0
send(client_socketfd,"welcome to login\n",,)
#接收函数 接受client对象的数据到buf中,一次接受bufferSize个长度,最后一个参数是flags 和send对应
recv(client_socketfd, buf, bufferSize, 0)
  • 完整程序

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

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

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <memory.h>

    TCP服务端Demo

#ifndef COMMUNICAITON_TCPSOCKET_H
#define COMMUNICAITON_TCPSOCKET_H
#include <stdio.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> #endif //COMMUNICAITON_TCPSOCKET_H
void tcpServerStart(); #include "TCPSocket.h"
const int bufferSize = ; void tcpServerStart(){
printf("server socket start init...\n");
int server_socketfd;//服务器套接字
int client_socketfd;//客户端套接字
int port = ;
struct sockaddr_in my_addr;//服务器网络地址结构
struct sockaddr_in remote_addr;//虚拟网络地址结构
socklen_t sin_size;//此处须运用长度定义类型 socketlen_t
char buf[bufferSize];//数据缓冲区
long sendLen = ;//发送接收长度
memset(&my_addr,,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,))<){
perror("socket init error");
return ;
}
/*将套接字绑定到服务器的网络地址上*/
if(bind(server_socketfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<){
perror("bind socket error");
return;
}
printf("server socket start listen ,port:%d",port);
/*监听连接请求--监听队列长度为5*/
listen(server_socketfd,); sin_size = sizeof(struct sockaddr_in); /*等待客户端连接请求到达*/
client_socketfd=accept(server_socketfd, (struct sockaddr *)&remote_addr,&sin_size);
if(client_socketfd < ){
perror("listen error");
return;
}
printf("accept %s",inet_ntoa(remote_addr.sin_addr));//打印客户端ip地址 sendLen=send(client_socketfd,"welcome to login\n",,);//发送欢迎信息
if(sendLen <= ){
perror("no send");
return;
}
while(sendLen=recv(client_socketfd, buf, bufferSize, )>){
printf("accept msg===");
printf("%s/n",buf);
}
close(client_socketfd);
close(server_socketfd); }

    UDP服务端Demo

#ifndef COMMUNICAITON_UDPSOCKET_H
#define COMMUNICAITON_UDPSOCKET_H #include <stdio.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif //COMMUNICAITON_UDPSOCKET_H void udpServerStart();
#include "UDPSocket.h"

const int bufSize = ;
void udpServerStart(){
printf("udp server init...\n");
int server_sockfd;
int len;
int port = ;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
socklen_t sin_size;//此处使用其自定义的socklen属性
char buf[bufSize];
memset(&my_addr,,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,))<){
perror("create socket error");
return;
}
/*将套接字绑定到服务器的网络地址上*/
if(bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<){
perror("bind socket error");
return;
}
sin_size = sizeof(struct sockaddr_in);
printf("waiting for package");
/*接收客户端的数据并将其发送给客户端--recvfrom是无连接的*/
if((len=recvfrom(server_sockfd,buf,bufSize,,(struct sockaddr *)&remote_addr,&sin_size))<){
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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <memory.h>
#endif //COMMUNICAITON_TCPCLIENT_H
void tcpClient(); #include "TCPClient.h"
const int bufSize = ;
void tcpClient(){
int client_fd;
int len;
struct sockaddr_in remote_addr;
char buf[bufSize];
memset(&remote_addr,, 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(); /*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/
if((client_fd=socket(PF_INET,SOCK_STREAM,))<){
perror("socket error");
return;
}
/*将套接字绑定到服务器的网络地址上*/
if(connect(client_fd,(struct sockaddr *)&remote_addr, sizeof(struct sockaddr))<){
perror("connect error");
return;
}
printf("connected to server\n");
len=recv(client_fd,buf,bufSize,);
printf("get msg :%s",buf);
close(client_fd); }

    UDP客户端 Demo

#ifndef COMMUNICAITON_UDPCLIENT_H
#define COMMUNICAITON_UDPCLIENT_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <memory.h>
#endif //COMMUNICAITON_UDPCLIENT_H void udpClient(); /*
* 向本地(localhost) 8000端口发送一个数据包
*/
const int buffSize = ;
void udpClient(){
int client_sockfd;
int len ;
struct sockaddr_in remote_addr;
int sin_size;
char buf[buffSize];
memset(&remote_addr,, 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(); /*创建客户端套接字--IPv4协议,面向无连接通信,UDP协议*/
if((client_sockfd=socket(PF_INET,SOCK_DGRAM,))<)
{
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),,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr)))<){
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();
}

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

Linux 套接字通信笔记(一)的更多相关文章

  1. linux 本地套接字通信

    本地套接字通信 利用本地套接字,也可以进程间通信. 本地套接字和有名管道一样都利用伪文件 管道的文件类型是p 本地套接字的文件类型是s. 当调用bind函数后,就会生成本地套接字对应的伪装文件 srw ...

  2. IPC——流套接字通信

    Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进 ...

  3. Linux 套接字编程中的 5 个隐患(转)

    本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...

  4. Python之路(第三十一篇) 网络编程:简单的tcp套接字通信、粘包现象

    一.简单的tcp套接字通信 套接字通信的一般流程 服务端 server = socket() #创建服务器套接字 server.bind() #把地址绑定到套接字,网络地址加端口 server.lis ...

  5. 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令

    1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...

  6. 【 Linux 】Linux套接字简要说明

    Linux套接字    源IP地址和目的IP地址以及源端口和目标端口号的组合称为套接字.其作用于标识客户端请求的服务器和服务. 套接字,支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间 ...

  7. 如何使用Linux套接字?

          我们知道许多应用程序,例如E-mail.Web和即时通信都依靠网络才能实现.这些应用程序中的每一个都依赖一种特定的网络协议,但每个协议都使用相同的常规网络传输方法.许多人都没有意识到网络协 ...

  8. 网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

    TCP协议:传输协议,基于端口工作 三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立 ...

  9. linux 套接字编程入门--Hello World

    下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...

随机推荐

  1. IE8以下支持css3 border-radius渲染方法

    这两天在做个集团网站,web前端妹子技术水平不咋样,写个web和wap 真够费劲的,对之前流行的H5和css3 响应式看来不太会用,扔给我一个半成品~~·非说各种canvas和border-radiu ...

  2. C语言点滴

    static修饰的变量和函数不可以在其他文件extern引用该变量或者函数. static变量放在静态内存区. static变量赋值只生效一次,再无法调用赋值语句.但是可以运算,例如++等. exte ...

  3. SPSS-单因素方差分析(ANOVA) 案例解析

    继续以上一期的样本为例,雌性老鼠和雄性老鼠,在注射毒素后,经过一段时间,观察老鼠死亡和存活情况. 研究的问题是:老鼠在注射毒液后,死亡和存活情况,会不会跟性别有关? 样本数据如下所示: (a代表雄性老 ...

  4. 3D indoor map positioning with a smartphone image

    menu 1. 基于Tango的三维建模技术(SLAM)(视觉SLAM,RGBD单目深度摄像机+罗盘仪)导出或不导出->Android 三维游戏开发技术(普通Android手机) 2. 基于An ...

  5. noip第9课作业

    1.    打印乘法表 [问题描述] 用for循环实现输出1至9的乘法表 [样例输出] 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4 ...

  6. android中Actionbar详解

    1.什么是Action BarAction Bar被认为是新版Android系统中最重要的交互元素,在程序运行中一直置于顶部,主要起到的作用在于:1)突出显示一些重要操作(如“最新”.“搜索”等)2) ...

  7. EBS _ALL, _TL, _VL, _V,_F,_VL,_A,_AVN and what else

    http://hi.baidu.com/einsteinalbert/item/54579250efc637abadc85705 _ALL, _TL, _VL, _V,_F,_VL,_A,_AVN a ...

  8. Accepted Technical Research Papers and Journal First Papers 【ICSE2016】

    ICSE2016 Accepted Paper Accepted Technical Research Papers and Journal First Papers Co-chairs: Wille ...

  9. what is HTTP OPTIONS verb

    The options verb is sent by browser to see if server accept cross origin request or not, this proces ...

  10. redis开机自启动脚本(linux)

    目前redis放在home下的文件夹中,写一个脚本,待系统启动的过程中,去启动该脚本. 脚本:redis.sh #!/bin/sh /home/juepei/Downloads/redis-3.0.0 ...