一、socket编程
socket本身有“插座“的意思,因此用来描述网络连接的一对一关系。”在TCP/IP协议中,“TP地址+TCP或端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。(socket就像当于文件一样,客户端通过往里面写数据,服务器端就从里面读取数据,socket 就是用来做载体的)。为TCP/TP协议设计的应用层编程接口称为socketAPI.
二、网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。TCP/IP协议规定,网络数据流应采用大端字节序,(即低地址存放在高字节)
例如地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8, 也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的, 接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题.
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
*************** h表示host,n表示network,l表示long,s表示short.例如:htonl表示将32位的长整数从主机字节序转换为网络字节序,******************
三、socket地址的数据类型及其相关函数
①、 sockaddr数据结构
1、struct sockaddr(这就相当于void*类型)
2、struct sockaddr_in
IPV4地址用 sockaddr_in结构体表示,包括16位端口号和32位IP 地址;IPV6地址用 sockaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。
②、绑定函数(bind)
绑定是将创建出来的socket和端口号绑定在一起,是这个创建出来的socket监听地址和端口号。
③、字符串转in_addr的函数
int inet_aton(const char* strptr,struct in_addr * addrptr);
int_addr_t inet_addr(const char* strptr);//将点分十进制的IP地址转换成32位的无符号×××
int inet_pton(int family,const char* strptr,void* addrptr);
④、in_addr转字符串的函数
char* inet_ntoa(struct in_addr inaddr);//将×××转换成点分十进制的IP地址
const char* inet_ntop(int family,const void* addrptr,char * strptr,size_t len);
⑤、监听(listen)
对于服务器端来说,需要一直保持一个监听的状态时刻监听网络中是否有连接请求,
⑥、接收(accept)
对于服务器端,当有连接请求的时候,需要一个套接字用于处理请求。
⑦、连接(conncect)
客户端用于发送请求连接的函数
—————————————————————————————————————————————
用例子说明:
一、服务器端:
①、首先创建套接字
②、添加本地信息(struct sockaddr_in)
③、绑定端口号(bind)
④、服务器监听是否有连接(listen)
⑤、接收获取连接(accepet)
#include#include #include #include #include #include #include #include static int start(char *_ip,int _port) { int listen_sock =socket(AF_INET,SOCK_STREAM,0);//创建套接字 if(listen_sock < 0) { printf("socket"); exit(1); } struct sockaddr_in local;//添加本地信息 local.sin_family=AF_INET; //协议家族 local.sin_port=htons(_port);//端口号 local.sin_addr.s_addr=inet_addr(_ip);//IP地址 if(bind(listen_sock ,(struct sockaddr *)&local,sizeof(local)) < 0)//绑定 { printf("bind"); exit(2); } if(listen(listen_sock ,5) < 0 )//监听 { perror("listen"); exit(3); } return listen_sock ; } void usage(char *proc) { printf("usage :%s[ip][port]\n",proc); } int main(int argc,char * argv[]) { if(argc != 3) { usage(argv[0]); exit(1); } int port= atoi(argv[2]); int sock=start(argv[1],port); struct sockaddr_in client; socklen_t len =sizeof(client); while(1) { int new_fd = accept(sock ,(struct sockaddr*)&client,&len); if(new_fd <0) { printf("accept\n"); continue; } printf("get aconnect... sock : %d,prot:%d ,ip:%s \n" ,new_fd,ntohs(client.sin_port),inet_ntoa(client.sin_addr)); char buf[1024]; while(1) { size_t size=read(new_fd,buf,sizeof(buf)-1); if(size > 0 )//read success { buf[size]='\0'; } else if(size == 0) { printf("client close\n"); break; } else { perror("read\n"); } printf("client: %s \n",buf); }
二、客户端
①、创建套接字
②、添加本地信息
③、建立连接
④、写入数据进行发送
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 void usage(char * _proc) 11 { 12 printf("usge:%s[remote ip]remote port[]\n",_proc); 13 } 14 int main(int argc,char* argv[]) 15 { 16 if(argc !=3) 17 { 18 usage(argv[0]); 19 exit(1); 20 } 21 int r_port=atoi(argv[2]); 22 char* r_ip=argv[1]; 23 24 int sock = socket(AF_INET,SOCK_STREAM,0);//创建套接字 25 if(sock < -1) 26 { 27 perror("sock"); 28 exit(1); 29 } 30 struct sockaddr_in remote;//添加本地信息 31 remote.sin_family = AF_INET; 32 remote.sin_port= htons(r_port); 33 remote.sin_addr.s_addr = inet_addr(r_ip); 34 35 int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));//建立连接 36 if(ret<0) 37 { 38 printf("connetct\n"); 39 } 40 char buf[1024]; 41 memset(buf,0,sizeof(buf)); 42 while(1) 43 { 44 printf("please enter::"); 45 scanf("%s",&buf); 46 write(sock,buf,sizeof(buf)-1);//写入数据 47 } 48 49 return 0; 50 }
结果如下:
socket套接字编程简单的来说就是创建一个公共的载体,客户端可以通过这个载体向服务器端发送数据,上面的这个程序,服务器一次只能接受一个客户端的连接,效率是很低下的;TCP是面向连接的,能够保证信息的可靠性,而UDP是无连接的。可靠性并不能够保证