大端节序:高位节放在低地址
小端节序:高位节放在高地址
PC多采用小端节序,而手机多采用大端节序,在网络传播过程中一律转换成大端节序,所以大端节序也称为网络字节序。
主要头文件#include <sys/socket.h>
linux提供了四个函数来完成主机字节序和网络字节序的转换,我常用的是
#include <netinet/in.h>
unsigned short int htons(unsigned short int hostshort);
TCP/IP有sockaddr_in和sockaddr_in6两个专用socket地质结构体,用于IPv4和IPv6,个人常用sockaddr_in
struct sockaddr_in
{
sa_family_t sin_family;//地址族
u_int16_t sin_port; //端口号
struct in_addr sin_addr; //IPv4地址结构体
} ;
struct in_addr
{
u_int32_t s_addr; //IPv4地址,要用网络字节序表示
};
||||||||||特别注意的是所有的专用socket地址类型的变量在使用的时候都需要转化为通用socket地址类型sockaddr,因为所有socket编程接口使用的地址参数的类型都是sockaddr.
IP地址转换函数
对于IPv4,用的是点分十进制字符串表示,但是编程中我们需要先把它们转化为整数(二进制)方能使用.
#include <arpa/inet.h>
int_addr_t inet_addr(const char* strptr);//作用是把原先的点分十进制字符串转换成网络字节序表示的IPv4地址.
(1) 创建socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
domain参数告诉系统使用哪个底层协议族AF_INET(OR PF_INET)表示的是IPv4
type用于指定服务类型,SOCK_STREAM(流服务),SOCK_DGRAM(数据报)服务。取用SOCK_STREAM表示用的是TCP协议,用SOCK_DGRAM则表示用的是UDP服务。
protocol通常设置为0
返回值:成功则返回一个文件描述符,失败就返回-1
(2)命名socket
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen);
这个操作客户端一般不用,他将一个socket与socket地址绑定在一起,这样客户端才知道如何连接他。
bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符
addrlen指出该socket地址的长度
bind成功返回0,失败返回-1.
(3)监听sockfd
sockfd被命名之后,我们还需要创建一个监听队列来存放待处理的客户连接。
#include <sys/socket.h>
int listen(int sockfd,int backlog);
sockfd指定被监听的sockfd,backlog提示内核监听队列的最大长度。只表示处于完全连接状态的socket的上限
(4)接受连接
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr* addr,socklen_t *addrlen);
addr的作用是用来监听远程地址
sockfd的作用是执行过listen系统调用的监听socket。
(5)发起连接
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr* serv_addr,socklen_t addrlen);
sockfd,是由系统调用产生的,第二个参数是监听的sockfd地址,addrlen指定地址长度
成功0,失败-1
(6)关闭连接
#include <unistd.h>
int close(int fd);
每使用一次fd引用计数减一,知道减到0为止。
(7)TCP数据读写
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
ssize_t send(int sockfd,const void* buf,size_t len,int flags);
向sockfd上读写数据,最后一个参数一般都是0
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5);
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
while(1)
{
if(c<0)
{
continue;
}
char buff[128] = {0};
recv(c,buff,127,0);
printf("%s",buff);
}
close(c);
return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;//虽然操作一样,但是客户端是为了去链接服务端
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);//转换成大端
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
//要用就必须先运行起来
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//链接到服务端上面
assert(res!=-1);
//执行到这个地方说明三次握手完成
while(1)
{
printf("input:\n");
char buff[128] = {0};
fgets(buff,128,stdin);//fgets会用到空格回车
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);//把收到的讯息再发送出去
memset(buff,0,128);
}
close(sockfd);//关闭
return 0;
}
ACK : TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1
SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
首先由Client发出请求连接即 SYN=1 ACK=0 (请看头字段的介绍), TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x
然后 Server 进行回复确认,即 SYN=1 ACK=1 seq=y, ack=x+1,
(为什么在连接的时候服务器端在接收到了客户端的SYN后返回的时候返回的是SYN=1 ACK=1...)的原因
作为补充
http://blog.csdn.net/oney139/article/details/8103223
这位前辈写的很详细,我做个记录方便以后复习