标签:internet address 计算机网络 ip地址 socket
>TCP协议位于传输层,是一种面向连接的可靠的传输协议
>socket(套接字):是IP地址与端口号的统称
>套接字的基本结构
struct sockaddr 这个结构用来存储套接字地址
结构体的定义
struct sockaddr {
unsigned short sa_family; /* address族, AF_xxx */
har sa_data[14]; /* 14 bytes的协议地址 */
};
sa_family 一般来说,都是“AFINET”。
sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。
为了处理struct sockaddr, 程序员建立了另外一个相似的结构 struct sockaddr_in:
struct sockaddr_in (“in” 代表 “Internet”)
struct sockaddr_in {
short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};
这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素
>IP 地址转换
Linux 系统提供和很多用于转换IP 地址的函数.首先,假设你有一个struct sockaddr_in ina,并且你的IP 166.111.69.52 ,你想把你的IP 存储到ina 中。你可以使用的函数: inet_addr() ,它能够把一个用数字和点表示IP 地址的字符串转换成一个无符号长整型。你可以像下面这样使用它:
ina.sin_addr.s_addr = inet_addr(“166.111.69.52”);
注意:
inet_addr() 返回的地址已经是网络字节顺序了,你没有必要再去调用htonl() 函数反过来,如果你有一个struct in_addr 并且你想把它代表的IP 地址打印出来(按照数字.数字.数字.数字的格式),那么你可以使用函数inet_ntoa()(“ntoa”代表“Network to ASCII”),它会把struct in_addr 里面存储的网络地址以数字.数字.数字.数字的格式。
l inet_ntoa() 使用struct in_addr 作为一个参数,不是一个长整型值。
>套接字字节转换程序的列表:
l htons()——“Host to Network Short”主机字节顺序转换为网络字节顺序(对无符号短型进行操作4 bytes)
l htonl()——“Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符号长型进行操作8 bytes)
l ntohs()——“Network to Host Short “ 网络字节顺序转换为主机字节顺序(对无符号短型进行操作4 bytes)
l ntohl()——“Network to Host Long “ 网络字节顺序转换为主机字节顺序(对无符号长型进行操作8 bytes)
>基本套接字调用
socket() 函数
取得套接字描述符
socket 函数的定义是下面这样子的:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain , int type , int protocol);
bind() 函数
bind()函数可以帮助你指定一个套接字使用的端口。
当你使用socket() 函数得到一个套接字描述符,你也许需要将socket 绑定上一个你的机器上的端口。当你需要进行口监听 listen()操作,等待接受一个连入请求的时候,一般都需要经过这一步。比如网络泥巴(MUD),Telnet a.b.c.d 4000.如果你只是想进行连接一台服务器,也就是进行 connect() 操作的时候,这一步并不是必须的。
bind()的系统调用声明如下:
#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd , struct sockaddr *my_addr , int addrlen) ;
参数说明:
l sockfd 是由socket()函数返回的套接字描述符。
l my_addr 是一个指向struct sockaddr 的指针,包含有关你的地址的信息:名称、端口和IP 地址。
addrlen 可以设置为sizeof(struct sockaddr)。
connect()函数
让我们花一点时间来假设你是一个Telnet 应用程序。你的使用者命令你建立一个套接字描述符。你遵从命令,调用了socket()。然后,使用者告诉你连接到“166.111.69.52”的23 端口(标准的Telnet 端口)你应该怎么做呢?
你很幸运:Telnet 应用程序,你现在正在阅读的就是套接字的进行网络连接部分:
connect()。
connect() 函数的定义是这样的:
#include <sys/types.h>
#include <sys/socket.h>
int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);
connect()的三个参数意义如下:
l sockfd :套接字文件描述符,由socket()函数返回的。
l serv_addr 是一个存储远程计算机的IP 地址和端口信息的结构。
l addrlen 应该是sizeof(struct sockaddr)。
listen() 函数
listen()函数是等待别人连接,进行系统侦听请求的函数。当有人连接你的时候,你有两步需要做:通过listen()函数等待连接请求,然后使用accept()函数来处理。(accept()函数在下面介绍)。
listen()函数调用是非常简单的。函数声明如下:
#include <sys/socket.h>
int listen(int sockfd, int backlog);
listen()函数的参数意义如下:
l sockfd 是一个套接字描述符,由socket()系统调用获得。
l backlog 是未经过处理的连接请求队列可以容纳的最大数目。
backlog 具体一些是什么意思呢?每一个连入请求都要进入一个连入请求队列,等待listen 的程序调accept((accept()函数下面有介绍)函数来接受这个连接。当系统还没有调用accept()函数的时候,如果有很多连接,那么本地能够等待的最大数目就是backlog 的数值。你可以将其设成5 到10 之间的数值
accept()函数
函数accept()有一些难懂。当调用它的时候,大致过程是下面这样的:
有人从很远很远的地方尝试调用 connect()来连接你的机器上的某个端口(当然是你已经在listen()的)。他的连接将被 listen 加入等待队列等待accept()函数的调用(加入等待队列的最多数目由调用listen()函数的第二个参数backlog 来决定)。你调用 accept()函数,告诉他你准备连接。accept()函数将回返回一个新的套接字描述符,这个描述符就代表了这个连接.好,这时候你有了两个套接字描述符,返回给你的那个就是和远程计算机的连接,而第一个套接字描述符仍然在你的机器上原来的那个端口上listen()。这时候你所得到的那个新的套接字描述符就可以进行send()操作和recv()操作了。
下面是accept()函数的声明:
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
accept()函数的参数意义如下:
l sockfd 是正在listen() 的一个套接字描述符。
l addr 一般是一个指向struct sockaddr_in 结构的指针;里面存储着远程连接过来的计算机的信息(比如远程计算机的IP 地址和端口)
> 下面我们就来模拟一个socket编程的TCP协议
server.c 的作用是接受client的请求,并与client进行简单的数据通信,整体为一个阻塞式的网络聊天工具
//server.c
1#include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/types.h>
4 #include<sys/socket.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<error.h>
8 #include<arpa/inet.h>
9 #include<pthread.h>
10 static void usage(const char* proc)
11 {
12 printf("Usage: %s [ip] [port]\n",proc);
13 }
14 void *thread_run(void* arg)
15 {
16 printf("creat a new thread\n");
17 int fd=(int)arg;
18 char buf[1024];
19 while(1)
20 {
21 memset(buf,‘\0‘,sizeof(buf));
22 ssize_t _s=read(fd,buf,sizeof(buf)-1);
23 if(_s>0)
24 {
25 printf("client#: %s\n",buf);
26 write(fd,buf,strlen(buf));
27 }
28 else if(_s==0)
29 {
30 printf("client close...\n");
31 break;
32 }
33 else
34 {
35 printf("read eror...\n");
36 break;
37 }
38 return (void*)0;
39 }
40 }
41 int main(int argc,char* argv[])
42 {
43 if(argc!=3)
44 {
45 usage(argv[0]);
46 exit(1);
47 }
48 int listen_sock=socket(AF_INET,SOCK_STREAM,0);
49 if(listen_sock<0)
50 {
51 perror("socket");
52 exit(2);
53 }
54 struct sockaddr_in server_socket;
55 server_socket.sin_family=AF_INET;
56 server_socket.sin_addr.s_addr=inet_addr(argv[1]);
57 server_socket.sin_port=htons(atoi(argv[2]));
58 int opt=1;
59 setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
60
61 if(bind(listen_sock,(struct sockaddr*)&server_socket,sizeof(server_socke t))<0)
62 {
63 perror("bind");
64 exit(3);
65 }
66 listen(listen_sock,5);
67 struct sockaddr_in peer;
68 socklen_t len=sizeof(peer);
69 int fd=accept(listen_sock,(struct sockaddr*)&peer,&len);
70 printf("fd: %d\n",fd);
71 if(fd<0)
72 {
73 perror("accept");
74 exit(4);
75 }
76 printf("get a new link,socket->[%s] [%d]",inet_ntoa(peer.sin_addr),ntohs (peer.sin_port));
77 while(1)
78 {
79 pthread_t id;
80 pthread_create(&id,NULL,thread_run,(void*)fd);
81 pthread_join(id,NULL);
82 }
83 return 0;
84 }
//client.c
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<netinet/in.h>
5 #include<arpa/inet.h>
6 #include<string.h>
7 #include<pthread.h>
8 #include<error.h>
9 #include<stdlib.h>
10 static void usage(const char *proc)
11 {
12 printf("usage: %s [ip] [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 sock=socket(AF_INET,SOCK_STREAM,0);
22 if(sock==0)
23 {
24 perror("socket");
25 exit(2);
26 }
27 struct sockaddr_in client_sock;
28 client_sock.sin_family=AF_INET;
29 client_sock.sin_addr.s_addr=inet_addr(argv[1]);
30 client_sock.sin_port=htons(atoi(argv[2]));
31
32 if(connect(sock,(struct sockaddr*)&client_sock,sizeof(client_sock))<0)
33 {
34 perror("connect");
35 exit(3);
36 }
37 char buf[1024];
38 while(1)
39 {
40 memset(buf,‘\0‘,sizeof(buf));
41 printf("Please Enter:");
42 fflush(stdout);
43 ssize_t _s=read(0,buf,sizeof(buf)-1);
44 if(_s>0)
45 {
46 buf[_s-1]=‘\0‘;
47 write(sock,buf,strlen(buf));
48 _s=read(sock,buf,sizeof(buf));
49 if(_s>0)
50 {
51 printf("%s\n",buf);
52 }
53 }
54 }
55 return 0;
56 }
运行结果:
本文出自 “11275984” 博客,请务必保留此出处http://11285984.blog.51cto.com/11275984/1835420
标签:internet address 计算机网络 ip地址 socket
原文地址:http://11285984.blog.51cto.com/11275984/1835420