TCP基本流程
No. | C/S | 函数 |
---|
1 | Server | socket() 、bind() 、listen() 、accept() 、recv() /read() 、send() /write() |
2 | Client | socket() 、connect() 、send() /write() 、recv() /read() |
服务器:
int socket(int domain, int type, int protocol)
No. | 参数 | 含义 |
---|
1 | domain | 协议域 | AF_INET :IPv4;AF_INET6 :IPv6;AF_LOCAL :Unix域 |
2 | type | 类型 | SOCK_STREAM :流式套接字;SOCK_DGRAM :数据报套接字;SOCK_RAW :原始套接字 |
3 | protocol | 协议 | 0 :自动根据type 匹配协议;IPPROTO_TCP /IPPROTO_UDP |
No. | 返回值 | 含义 |
---|
1 | -1 | 失败 |
2 | >0 | socket描述符 |
int bind(int socket, const struct sockaddr* address, socklen_t address_len)
No. | 参数 | 含义 |
---|
1 | socket | 套接字描述符 |
2 | address | 地址和端口号 |
3 | address_len | address缓冲区的长度 |
No. | 返回值 | 含义 |
---|
1 | 0 | 成功 |
2 | SOCKET_ERROR | 失败 |
int listen(int sockfd, int backlog)
No. | 参数 | 含义 |
---|
1 | sockfd | 监听的socket描述符 |
2 | backlog | 排队的最大连接个数 |
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
No. | 参数 | 含义 |
---|
1 | sockfd | 服务器的socket描述符,监听socket描述符 |
2 | addr | 客户端的socket地址 |
3 | addrlen | 客户端的socket地址的长度 |
ssize_t read(int fd, void *buf, size_t len);
No. | 参数 | 含义 |
---|
1 | fd | 文件描述符 |
2 | buf | 读取数据 |
3 | len | 读取数据的长度 |
No. | 返回值 | 含义 |
---|
1 | 0 | 读到文件的结束 |
2 | >0 | 实际所读的字节数 |
3 | <0 | 出错 |
ssize_t write(int fd, const void *buf, size_t len);
No. | 参数 | 含义 |
---|
1 | fd | 文件描述符 |
2 | buf | 写入数据 |
3 | len | 写入数据的长度 |
int close(int sockfd)
int shutdown(int sockfd,int howto)
No. | 参数 | 含义 |
---|
1 | sockfd | socket套接字 |
2 | howto | 关闭方式 |
No. | 方式 | 值 | 含义 |
---|
1 | SHUT_RD | 0 | 关闭连接的读 |
2 | SHUT_WR | 1 | 关闭连接的写 |
3 | SHUT_RDWR | 2 | 连接的读和写都关闭 |
客户端:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
No. | 参数 | 含义 |
---|
1 | sockfd | 客户端的socket描述字 |
2 | addr | 服务器的socket地址 |
3 | addrlen | 服务器的socket地址的长度 |
ip地址转为网络字节序IP
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main(int argc,char* argv[]){
if(2 != argc){
printf("usage:%s <ip>\n",argv[0]);
return 1;
}
struct in_addr addr;
int res = inet_aton(argv[1],&addr); //点分十进制数串转网络字节序长整型
if(0 == res){
perror("inet_aton error");
return 1;
}
printf("res:%d\n%s = 0x%08x",res,argv[1],addr);
return 0;
}
[kiosk@foundation38 ~]$ ./a.out 172.0.0.1
res:1
172.0.0.1 = 0x010000ac //转化成网络的大端字节序
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
int main(int argc,char* argv[]){
if(argc!=4){
printf("usage:%s IP Port Message\n",argv[0]);
return 1;
}
//创建套结字
int fd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family=AF_INET;
if(inet_aton(argv[1],&addr.sin_addr)==0)//点分十进制->网络序IP
{
printf("unvaild");
}
addr.sin_port=htons(atoi(argv[2]));
if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))!=0){
perror("connect error");
return 1;
}
write(fd,argv[3],strlen(argv[3]));
close(fd);
}
#include<stdio.h>
#include<arpa/inet.h>
#include<sys/socket.h>
int main(int argc,char* argv[]){
//创建监听套结字
int fd=socket(AF_INET,SOCK_STREAM,0);
//绑定套结字地址
//创建地址
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[2]));//主机序->网络序
inet_aton(argv[1],&addr.sin_addr);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))!=0){
perror("bind error");
return 1;
}
//设置监听
if(listen(fd,4)!=0){
perror("listen error");
return 1;
}
//创建链接套结字
int connfd=accept(fd,NULL,NULL);
//读数据
char temp[1024];
read(connfd,temp,sizeof(temp));
printf("%s\n",temp);
//关闭套结字
close(connfd);
close(fd);
}
运行结果
客户端:
[root@foundation38 net]# ./client 127.0.0.1 8080 hello
服务器:
[root@foundation38 net]# ./server 127.0.0.1 8080
hello //接收到hello
UDP:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
No. | 参数 | 含义 |
---|
1 | sockfd | sockfd文件描述符 |
2 | buf | 写入数据 |
3 | len | 写入数据的长度 |
4 | flags | 通常为0 |
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
No. | 参数 | 含义 |
---|
1 | sockfd | sockfd文件描述符 |
2 | buf | 写入数据 |
3 | len | 写入数据的长度 |
4 | flags | 通常为0 |
5 | dest_addr | 目标socket地址 |
6 | addrlen | 目标socket地址长度 |
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
No. | 参数 | 含义 |
---|
1 | fd | 文件描述符 |
2 | buf | 读取数据 |
3 | len | 读取数据的长度 |
4 | flags | 通常为0 |
No. | 返回值 | 含义 |
---|
1 | 0 | 读到文件的结束 |
2 | >0 | 实际所读的字节数 |
3 | <0 | 出错 |
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)
No. | 参数 | 含义 |
---|
1 | fd | 文件描述符 |
2 | buf | 读取数据 |
3 | len | 读取数据的长度 |
4 | flags | 通常为0 |
5 | dest_addr | 目标socket地址 |
6 | addrlen | 目标socket地址长度 |
No. | 返回值 | 含义 |
---|
1 | 0 | 读到文件的结束 |
2 | >0 | 实际所读的字节数 |
3 | <0 | 出错 |
服务器:
#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
int main(int argc,char* argv[]){
int fd=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[2]));
addr.sin_addr.s_addr=inet_addr(argv[1]);
bind(fd,(struct sockaddr*)&addr,sizeof(addr));
while(1){
char* data[512]={0};
recv(fd,data,sizeof(data),0);
printf("%s\n",data);
}
close(fd);
}
客户端:
#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
int main(int argc,char* argv[]){
if(argc!=3){
printf("Usage:%s IP Port\n",argv[0]);
return 1;
}
int fd=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&addr.sin_addr);
while(1){
char data[512]={0};
scanf("%s",data);
sendto(fd,data,strlen(data)+1,0,(struct sockaddr*)&addr,sizeof(addr));
}
close(fd);
}