Linux 套接字通信笔记(一)
- 协议
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 套接字通信笔记(一)的更多相关文章
- linux 本地套接字通信
本地套接字通信 利用本地套接字,也可以进程间通信. 本地套接字和有名管道一样都利用伪文件 管道的文件类型是p 本地套接字的文件类型是s. 当调用bind函数后,就会生成本地套接字对应的伪装文件 srw ...
- IPC——流套接字通信
Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进 ...
- Linux 套接字编程中的 5 个隐患(转)
本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...
- Python之路(第三十一篇) 网络编程:简单的tcp套接字通信、粘包现象
一.简单的tcp套接字通信 套接字通信的一般流程 服务端 server = socket() #创建服务器套接字 server.bind() #把地址绑定到套接字,网络地址加端口 server.lis ...
- 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令
1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...
- 【 Linux 】Linux套接字简要说明
Linux套接字 源IP地址和目的IP地址以及源端口和目标端口号的组合称为套接字.其作用于标识客户端请求的服务器和服务. 套接字,支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间 ...
- 如何使用Linux套接字?
我们知道许多应用程序,例如E-mail.Web和即时通信都依靠网络才能实现.这些应用程序中的每一个都依赖一种特定的网络协议,但每个协议都使用相同的常规网络传输方法.许多人都没有意识到网络协 ...
- 网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法
TCP协议:传输协议,基于端口工作 三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立 ...
- linux 套接字编程入门--Hello World
下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...
随机推荐
- IE8以下支持css3 border-radius渲染方法
这两天在做个集团网站,web前端妹子技术水平不咋样,写个web和wap 真够费劲的,对之前流行的H5和css3 响应式看来不太会用,扔给我一个半成品~~·非说各种canvas和border-radiu ...
- C语言点滴
static修饰的变量和函数不可以在其他文件extern引用该变量或者函数. static变量放在静态内存区. static变量赋值只生效一次,再无法调用赋值语句.但是可以运算,例如++等. exte ...
- SPSS-单因素方差分析(ANOVA) 案例解析
继续以上一期的样本为例,雌性老鼠和雄性老鼠,在注射毒素后,经过一段时间,观察老鼠死亡和存活情况. 研究的问题是:老鼠在注射毒液后,死亡和存活情况,会不会跟性别有关? 样本数据如下所示: (a代表雄性老 ...
- 3D indoor map positioning with a smartphone image
menu 1. 基于Tango的三维建模技术(SLAM)(视觉SLAM,RGBD单目深度摄像机+罗盘仪)导出或不导出->Android 三维游戏开发技术(普通Android手机) 2. 基于An ...
- 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 ...
- android中Actionbar详解
1.什么是Action BarAction Bar被认为是新版Android系统中最重要的交互元素,在程序运行中一直置于顶部,主要起到的作用在于:1)突出显示一些重要操作(如“最新”.“搜索”等)2) ...
- 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 ...
- Accepted Technical Research Papers and Journal First Papers 【ICSE2016】
ICSE2016 Accepted Paper Accepted Technical Research Papers and Journal First Papers Co-chairs: Wille ...
- what is HTTP OPTIONS verb
The options verb is sent by browser to see if server accept cross origin request or not, this proces ...
- redis开机自启动脚本(linux)
目前redis放在home下的文件夹中,写一个脚本,待系统启动的过程中,去启动该脚本. 脚本:redis.sh #!/bin/sh /home/juepei/Downloads/redis-3.0.0 ...