linux C ----- udp, tcp, unix socket通信简单例子
udp socket
相关知识
udp的程序设计可以分成客户端和服务器端两个部分。两者的主要差别在于对地址的绑定函数,客户端可以不用进行地质和端口的绑定。(客户端是随机拿一个大于1024的端口去连接的)
和tcp相比,udp缺少connect(),listen(),accept()函数 【因为tcp面向连接,而udp是无连接的。】
服务端的udp:
动作 | 函数 |
---|---|
创建 | socket() |
绑定 | bind() |
发送 | sendto() |
接收 | recvfrom() |
关闭 | close() |
客户端和服务端相比没有绑定bind()的步骤。
服务端的recvfrom是阻塞的,直到接收到数据。
关键词:数据包套接字,套接字文件描述符。
socket常见的套接字类型:
- af_inet(又称 pf_inet)是ipv4网络协议的套接字类型
- af_inet6 是ipv6网络协议的套接字类型
- af_unix 属于unix本地通信
socket常见的套接字选项:
sock_stream | sock_dgram |
---|---|
数据流 | 数据包 |
有保障 | 无保障 |
面向连接 | 面向无连接 |
tcp/ip | udp |
int s=socket(af_inet,sock_dgram,0); if(s==-1){ perror("create socket: "); return -1; } struct sockaddr serv; serv.sin_family=af_inet; serv.sin_addr.s_addr=htol(inaddr_any); // 任意本地ip,网络字节序 serv.sin_port=htos(port); //网络字节序 bind(s,(struct sockaddr*)&serv,sizeof(serv)); //绑定套接字和地址
解释“绑定套接字和地址”,实质上是指明发送数据的ip和端口。
它们的联系:
udp socket 例子
编写一个程序,使用udp通信,client是10.21.1.142, server是10.21.1.229,port是3000. client发送end能使得程序结束。
客户端:
#include #include #include #include #include #include #define port 3000 int main(){ int s=socket(af_inet,sock_dgram,0); if(s==-1){ perror("create socket error: "); exit(1); } struct sockaddr_in serv; bzero(&serv,sizeof(serv)); serv.sin_family=af_inet; serv.sin_addr.s_addr = inet_addr("10.21.1.229"); //htol(inaddr_any); serv.sin_port=htons(port); char buff[105]; int ret; while(1){ ret=read(stdin_fileno,buff,105); if(ret==-1){ perror("read error: "); break; } buff[ret]=0; sendto(s,buff,strlen(buff),0,(struct sockaddr *)&serv,sizeof(serv)); if(strcmp(buff,"end\n")==0){ printf("client process end.\n"); break; } int addr_len=sizeof(serv); if((ret=recvfrom(s,buff,105,0,(struct sockaddr *)&serv,&addr_len))==-1){ perror("recvform error: "); break; } buff[ret]=0; printf("receive message from server: %s",buff); } close(s); return 0; }
服务端:
#include #include #include #include #include #include #define port 3000 int main(){ int s=socket(af_inet,sock_dgram,0); if(s==-1){ perror("create socket error: "); exit(1); } struct sockaddr_in serv,client; bzero(&serv,sizeof(serv)); serv.sin_family=af_inet; serv.sin_addr.s_addr=inet_addr("10.21.1.229");//htol(inaddr_any); serv.sin_port=htons(port); //网络字节序 if(bind(s,(struct sockaddr*)&serv,sizeof(serv))==-1){//绑定套接字和地址 perror("bind error: "); exit(1); } while(1){ char buff[105]; int addr_len=sizeof(client); int ret=recvfrom(s,buff,105,0,(struct sockaddr *)&client,&addr_len); // once success, we get client. if(ret==-1){ perror("recvfrom error: "); break; } buff[ret]=0; if(strcmp(buff,"end\n")==0){ printf("server process end.\n"); break; } printf("receive message from client: %s",buff); ret=read(stdin_fileno,buff,sizeof(buff)); if(ret<0){ perror("read error: "); break; } if(sendto(s,buff,ret,0,(struct sockaddr *)&client,addr_len)==-1){ perror("sendto error: "); break; } } close(s); return 0; }
会话:
$ ./udp1 hello, i'm client receive message from server: i'm server, i got message. oh, congratulation. receive message from server: hahaha end client process end. $ ./udp1 receive message from client: hello, i'm client i'm server, i got message. receive message from client: oh, congratulation. hahaha server process end.
tcp socket
相关知识
通用的套接字地址
struct sockaddr { unsigned short int sa_family; char sa_data[14]; };
用户和内核进行数据交互:
得到数据: recv(), accept()
传入数据: send(), bind()
表示地址长度的参数在得到数据的函数中是传地址的, 而在传入数据的函数则是传值的. (对比accept和bind就知道这是正确的.)
tcp server and client work as:
tcp socket 例子
编写tcp socket通信例子, 分为客户端和服务端部分,当客户端发送”end”时,结束程序.
tcp_server.c:
#include #include #include #include #include #include #include const int port = 3000; const int max = 10; /* biggest number of connected clients */ const char ip[] = "192.168.123.4"; int main(){ int server_fd=socket(af_inet,sock_stream,0); if(server_fd == -1){ perror("socket: "); return -1; } struct sockaddr_in server; bzero(&server,sizeof(server)); server.sin_family=af_inet; server.sin_addr.s_addr=htonl(inaddr_any); //inet_addr(ip); /* both ways are ok. */ server.sin_port=htons(port); if(bind(server_fd,(struct sockaddr *)&server,sizeof(server))==-1){ perror("bind: "); return -1; } if(listen(server_fd,max) == -1){ perror("listen: "); return -1; } struct sockaddr_in client; int client_len=sizeof(client); int conn = accept(server_fd, (struct sockaddr *)&client, &client_len); if(conn == -1){ perror("accept: "); return -1; } char buff[105]; while(1){ memset(buff,0,sizeof(buff)); if(read(conn,buff,sizeof(buff)) == -1){ perror("read: "); break; } if(strcmp(buff,"end\n") == 0){ puts("the server process end. "); break; } printf("recv message from client: %s", buff); memset(buff,0,sizeof(buff)); if(read(stdin_fileno,buff,sizeof(buff)) == -1){ perror("read: "); break; } if(write(conn,buff,strlen(buff)) == -1){ perror("send: "); break; } } close(conn); close(server_fd); return 0; }
tcp_client.c:
#include #include #include #include #include #include #include const int port = 3000; const int max = 10; /* biggest number of client_fdected clients */ const char ip[] = "192.168.123.4"; int main(){ int client_fd=socket(af_inet,sock_stream,0); if(client_fd == -1){ perror("socket: "); return -1; } struct sockaddr_in server; bzero(&server,sizeof(server)); server.sin_family=af_inet; server.sin_addr.s_addr=inet_addr(ip); server.sin_port=htons(port); if(connect(client_fd,(struct sockaddr *)&server,sizeof(server))==-1){ perror("client_fdect: "); return -1; } char sends[105],recvs[105]; while(1){ read(stdin_fileno,sends,sizeof(sends)); if(send(client_fd,sends,strlen(sends),0)==-1){ perror("send: "); break; } if(strcmp(sends,"end\n") == 0){ puts("the client end."); break; } memset(recvs,0,sizeof(recvs)); if(read(client_fd,recvs,sizeof(recvs))==-1){ perror("recv: "); break; } printf("recv message from server: %s",recvs); memset(sends,0,sizeof(sends)); } close(client_fd); return 0; }
会话:
./tcps recv message from client: hello i got your message. recv message from client: ok, every thins seems good. client, we works. the server process end. ./tcpc hello recv message from server: i got your message. ok, every thins seems good. recv message from server: client, we works. end the client end.
unix socket
相关知识
unix域协议族用于同一台主机上客户机、服务器通信。
unix域中两种类型的套接字:字节流套接字(类似于tcp)、数据包套接字(类似于udp)。
unix域套接字的传输速度是tcp的两倍。
unix域套接字和传统套接字相比,他是用路径名来表示协议族的描述。
unix域地质结构:
#define unix_path_max 108 struct sockaddr_un { __kernel_sa_family_t sun_family; /* af_unix */ char sun_path[unix_path_max]; /* pathname */ };
sun_family: af_unix (known as af_local)
sun_path: 必须是绝对路径,文件默认访问权限是0777
unix socket例子
一个客户端和服务器通信(本地)的例子. 当客户端发送end时,结束会话.
un_sock_serv.c:
#include #include #include #include #include const char path[]="/tmp/server"; int main(){ int server_fd,client_fd; struct sockaddr_un server_addr, client_addr; unlink(path); server_fd = socket(af_unix,sock_stream,0); if(server_fd == -1){ perror("socket: "); exit(1); } server_addr.sun_family=af_unix; strcpy(server_addr.sun_path,path); if(bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1){ perror("bind: "); exit(1); } listen(server_fd,10); //server listen most 10 requests. puts("server is listening: "); int client_len=sizeof(client_addr); client_fd=accept(server_fd,(struct sockaddr *)&client_addr,(int *)&client_len); if(client_fd == -1){ perror("accept: "); exit(1); } char recv[105], send[105]; int i; while(1){ memset(recv,0,sizeof(recv)); if(read(client_fd,recv,105)==-1){ perror("read: "); break; } if(strcmp(recv,"end\n")==0){ printf("the server process end.\n"); break; } printf("recv message from client: %s",recv); memset(send,0,sizeof(send)); if(read(stdin_fileno,send,sizeof(send))==-1){ perror("read: "); break; } if(write(client_fd,send,strlen(send))==-1){ perror("write: "); break; } } close(server_fd); unlink(path); }
un_sock_client.c:
#include #include #include #include #include const char path[]="/tmp/server"; int main(){ int server_fd,client_fd; struct sockaddr_un server_addr, client_addr; //unlink(path); server_fd = socket(af_unix,sock_stream,0); if(server_fd == -1){ perror("socket: "); exit(1); } server_addr.sun_family=af_unix; strcpy(server_addr.sun_path,path); if(connect(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1){ perror("connect: "); exit(1); } char recv[105],send[105]; int i; puts("the client started, please enter your message: "); while(1){ memset(send,0,sizeof(send)); if(read(stdin_fileno,send,105)==-1){ perror("read: "); break; } if(write(server_fd,send,strlen(send))==-1){ perror("send: "); break; } if(strcmp(send,"end\n")==0){ printf("the client process end.\n"); break; } memset(recv,0,sizeof(recv)); if(read(server_fd,recv,105)==-1){ perror("recv: "); break; } printf("recv message from server: %s",recv); } close(server_fd); unlink(path); return 0; }
会话:
$ ./exes server is listening: recv message from client: hello, i'm client i'm server, i get your message. recv message from client: ok, it seems goods. yeah, it works. the server process is end. $ ./exec the client started, please enter your message: hello, i'm client recv message from server: i'm server, i get your message. ok, it seems goods. recv message from server: yeah, it works. end the client process end.
推荐阅读
-
linux C ----- udp, tcp, unix socket通信简单例子
-
基于Linux用C语言实现TCP半双工通信和UDP半双工通信
-
linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
-
C#基于Socket的UDP和TCP处理通信报文开发传输
-
Linux C之Socket通信(UDP协议)
-
c/c++ linux 进程间通信系列2,使用UNIX_SOCKET
-
详解C# Socket简单例子(服务器与客户端通信)
-
Windows下C语言的Socket编程例子(TCP和UDP)
-
Windows下C语言的Socket编程例子(TCP和UDP)
-
Day.55————C++ socket编程实现简单的UDP、TCP通信(服务端+客户端)