一、socket
在Linux中的网络编程是通过socket接口来进行的。人们常说的socket接口是一种特殊的I/O,它也是一种文件描述符。每一个socket都用一个半相关描述{协议,本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议,本地地址、本地端口、远程地址、远程端口}。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的。
二、socket常用API
1.创建套接字
int socket(int domain, int type, int protocol);
domain:域。
AF_INET/PF_INET:网际协议
AF_UNIX/PF_UNIX:本地协议,可写成AF_LOCAL/PF_LOCAL
type:类型。
SOCK_STREAM:流式套接字
SOCK_DGRAM:数据报套接字
protocol:协议。
一般为0
返回值:
成功:待连接套接字
失败:-1
备注:在网际协议中,选择流式套接字就代表TCP协议,选择数据报套接字就代表UDP协议,第三个参数protocol一般都不用。
2、绑定套接字与网络地址
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:待连接套接字
addr:包含本地地址(IP+PORT)的通用地址结构体的指针
addrlen:地址结构体大小
通用地址结构体的定义:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
};
特殊地址结构体 —— IPv4地址结构体:
struct sockaddr_in
{
u_short sin_family; // 地址族
u_short sin_port; // 端口
struct in_addr sin_addr; // IPV4地址
char sin_zero[8];
};
struct in_addr
{
in_addr_t s_addr; // 无符号32位网络地址
};
3.将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数
int listen(int sockfd, int backlog);
sockfd:待连接套接字
backlog:最大同时接收连接请求个数
返回值:
成功:0,并将sockfd设置为监听套接字
失败:-1
4、等待对端连接请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:监听套接字
addr:通用地址结构体,用以存储对端地址(IP+PORT)
addrlen:参数addr的存储区域大小
返回值:
成功:已连接套接字(非负整数)
失败:-1
5、连接对端监听套接字
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:待连接套接字
addr:包含对端地址(IP+PORT)的通用地址结构体的指针
addrlen:地址结构体大小
返回值:
成功:0
失败:-1
6.断开本端连接套接字
int close(int fd);
fd:已连接套接字
返回值:
成功:0
失败:-1
7.字节序转换
uint32_t htonl(uint32_t hostlong); //h -> host 主机 n ->net 网络
uint16_t htons(uint16_t hostshort); //l -> long 长4 s -> short 短2
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
hostlong: 主机字节序的长整型数据
hostshort: 主机字节序的短整型数据
netlong: 网络字节序的长整型数据
netshort: 网络字节序的短整型数据
返回值:
对应的字节序数据
三、TCP demo
服务端
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int s_fd;
int c_fd;
int pid;
char sendbuf[128];
char recvbuf[128];
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
//2.bind
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(s_fd,(struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));
//3.listen
listen(s_fd, 10);
//4.accept
int c_len = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr, &c_len);
if(c_fd == -1){
perror("accept");
exit(-1);
}
printf("========客户端已连接========\n");
pid = fork();
if(pid == 0){
while(1){
memset(recvbuf,0,sizeof(recvbuf));
read(c_fd,recvbuf, 128);
if(strstr(recvbuf,"quit") != NULL){
write(c_fd,"client quit",20);
printf("========客户端已退出========\n");
break;
}else{
printf("客户端: %s",recvbuf);
}
}
}
else if(pid > 0){
while(1){
memset(sendbuf,0,sizeof(sendbuf));
fgets(sendbuf,128,stdin);
write(c_fd,sendbuf, strlen(sendbuf));
}
}
}
close(s_fd);
close(c_fd);
return 0;
}
客户端
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int c_fd;
int pid;
char sendbuf[128];
char recvbuf[128];
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
c_fd = socket(AF_INET, SOCK_STREAM, 0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
//2.connect
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
connect(c_fd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr_in));
//printf("==============连接成功==============\n");
pid = fork();
if(pid > 0){
while(1){
memset(recvbuf,0,sizeof(recvbuf));
read(c_fd,recvbuf, 128);
if(strstr(recvbuf,"client quit") != NULL){
printf("==============成功退出==============\n");
exit(0);
}
printf("服务端: %s",recvbuf);
}
}
else if(pid == 0){
while(1){
memset(sendbuf,0,sizeof(sendbuf));
fgets(sendbuf,128,stdin);
write(c_fd,sendbuf, strlen(sendbuf));
if(strstr(sendbuf,"quit") != NULL){
exit(0);
}
}
}
close(c_fd);
return 0;
}
四、UDP demo
服务端
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int s_fd;
char sendbuf[128];
char recvbuf[128];
socklen_t len;
struct sockaddr_in s_addr,c_addr;
//1.socket
s_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
//2.bind
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(s_fd, (struct sockaddr*)&s_addr, sizeof(s_addr));
len = sizeof(struct sockaddr_in);
while(1){
//3.recvfrom
memset(recvbuf, 0, sizeof(recvbuf));
recvfrom(s_fd, recvbuf, 128, 0, (struct sockaddr*)&c_addr, &len);
if(strstr(recvbuf,"quit") != NULL){
printf("==============客户端已退出==============\n");
}else{
printf("client:%s",recvbuf);
}
//4.sendto
memset(sendbuf, 0, sizeof(sendbuf));
fgets(sendbuf,128,stdin);
if(strstr(sendbuf,"quit") != NULL){
printf("==============服务端已退出==============\n");
break;
}
sendto(s_fd, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&c_addr, len);
}
close(s_fd);
return 0;
}
客户端
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int c_fd;
char sendbuf[128];
char recvbuf[128];
socklen_t len;
struct sockaddr_in s_addr,c_addr;
//1.socket
c_fd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
printf("==============连接成功==============\n");
len = sizeof(struct sockaddr_in);
while(1){
//2.sendto
memset(sendbuf, 0, sizeof(sendbuf));
fgets(sendbuf,128,stdin);
sendto(c_fd, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&s_addr, len);
if(strstr(sendbuf,"quit") != NULL){
printf("==============成功退出==============\n");
break;
}
//3.recvfrom
memset(recvbuf, 0, sizeof(recvbuf));
recvfrom(c_fd, recvbuf, 128, 0, (struct sockaddr*)&c_addr, &len);
printf("server:%s",recvbuf);
}
close(c_fd);
return 0;
}