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和端口。
关于sockaddr和sockaddr_in的区别:
它们的联系:
udp socket 例子
编写一个程序,使用udp通信,client是10.21.1.142, server是10.21.1.229,port是3000. client发送end能使得程序结束。
客户端:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#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"); //htonl(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 <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#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 <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
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 <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
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
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 <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
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 <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
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.