一:引子
在网络五层中:数据链路层-----------------------------------MAC地址
网际层----------------------------------------IP地址
传输层----------------------------------------IP地址:端口号
二:端口
有了网络地址,就可以唯一标识网络上的每台计算机,但是在一台计算机上面可以同时运行多个程序,而他们可能同时要访问网络,对于一台计算机上的多个应用程
序,TCP 和 UDP协议采用了16位的端口号来标识他们。一台主机上的不同进程可以绑定到不同的端口上,这些进程都可以访问网络而互不干扰。
0---------1023 知名端口 由权威机构规定其用途
1024-----65535 自由端
三:相关数据结构
1、套接字地址结构 struct sockaddr{ unsigned short sa_family; char sa_data[14];};
sa_family : 表示套接字的协议类型,对应于TCP/IP协议该值为 AF_INET;
sa_data : 用于存储具体的协议地址,他等价于一个数据结构:sockadd_in
2、TCP/IP地址协议族格式:struct sockaddr_in { unsigned short sin_family; unsigned short int sin_port; struct
in_addr sin_addr ; unsigned char sin_zero[8]; };
sin_family: 表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能为AF_INET。
sin_port : 表示端口号
sin_addr : 用于存储32位的IP地址
sin_zero : 该数组作为填充字段,一般赋值为0
3、struct in_addr {unsigned long s_addr};
四、调用函数
I :创建套接字 int socket (int domain, int type , int protocol)
--------domain用于指定创建套接字所使用的协议族。
AF_UNIX # 创建只在本机进行通信的套接字;
AF_INET # 使用IPv4TCP/IP协议;
AF_INET6 # 使用IPv6TCP/IP协议
---------type用于指定套接字的类型。
SOCK_STREAM # 创建TCP流套接字;
SOCK_DGRAM # 创建DUP套接字;
SOCK_RAW # 创建原始套接字;
----------protocol通常设定为0,表示通过参数domain指定的协议族和参数type指定的套接字类型来确定使用的协议。
II:建立连接 int connect (int sockfd, const struct sockaddr * serv_addr,socklen_t addrlen)
---------sockfd是由一个函数socket创建的套接字
--------- addrlen是serv_addr的长度
III:绑定套接字 int bind (int sockfd , struct sockaddr * my_addr, socklen_t addrlen)
--------对于只有一个IP地址的计算机表示本机的IP地址,对于有多个IP地址则表示本服务程序将处理来自所有网
络接口上相应端口的连接请求。
IV:在套接字上创建监听 int listen(int s, int len)
---------通过函数socket()创建的字是主动套接字,这种套接字可以用来主动请求链接到某个服务器,但是作为服
务器端的程序,通常在某个端口上监听等待来自客户端的连接请求。
---------通过listen将该套接字转换为监听套接字,等待来自于客户端的连接请求。一般多个客户可以连接到一个服务器上,服务器向这些客户端提供某种服务,服务器端设置一个连接队列,记录已经建立的连接,参数len指定了该连接队列的最大长度。
IIV:接受连接 int accept(int s, struct sockaddr *addr , socklen_t *addrlen)
---------s 是由函数socket创建,经过函数bind绑定的到本地某一个端口上,然后通过函数listen转换而来的监听套
接字
---------addr 用来保存发起连接请求的主机的地址和端口
---------addrlen 是参数addr所指向的结构体的大小
IIIV:ssize_t send(int s, const void *msg, size_t len , int flags)
-------------s是已经建立好的套接字描述符
-------------flags是控制选项
MSG_OOB # 在指定的套接字上发送带外数据,该类型的套接字必须支持带外数据
MSG_DONTROUTE # 通过最直接的路径发送数据,而忽略下层协议的路由设置
ssize_t recv(int socked,const void *msg, size_t len , int flags)
-------------flags是控制选项
MSG_OOB # 请求接收带外数据
MSG_PEEK # 查看数据而不读出
MSG_WAITALL # 只在接收缓冲区满时才返回
四:C/S 结构模型图
五:程序实例
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<sys/socket.h>
- #include<string.h>
- #include<unistd.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- #define USERNAME 0
- #define USERPASS 1
- #define PORT_SERV 4055
- #define LISTENL 12
- #define BUFSIZE 1024
- struct userinfo{
- char username[32];
- char userpass[32];
- };
- typedef struct userinfo userinfo_c;
- userinfo_c users[]={{"linux","unix"},{"787","007"},{"gyeve","gaoyi"}};
- int send_data(int con,char *buf)
- {
- int ret;
- ret=send(con,buf,sizeof(buf),0);
- if(ret<=0){
- printf("send is wrong\n");
- return ret;
- }
- return ret;
- }
- int find_name(char *name)
- {
- int index=0;
- for(index=0;index<3;index++)
- {
- printf("name = %s username = %s\n",name,users[index].username);
- if(strcmp(users[index].username,name)==0)
- return index;
- }
- return -1;
- }
- int main()
- {
- int socket_id,optval,user_id,accpt_len;
- struct sockaddr_in server_ad,client_ad;
- int acc_res, ret,flag=USERNAME;
- pid_t pid;
- char buf[BUFSIZE];
- socket_id = socket(AF_INET,SOCK_STREAM,0);
- if(socket_id <=0) {
- perror("socket");
- exit(1);
- }
- optval=1;
- if(setsockopt(socket_id,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int))<0){/*设置窗口重新绑定*/
- perror("setsockopt");
- exit(2);
- }
- memset(&server_ad,0,sizeof(struct sockaddr_in));
- server_ad.sin_family = AF_INET; /*ipv4 of the tcp/ip protocol */
- server_ad.sin_port = htons(PORT_SERV);
- server_ad.sin_addr.s_addr = htonl(INADDR_ANY);/* the localhost ip address */
- if(bind(socket_id,(struct sockaddr *)&server_ad,sizeof(struct sockaddr_in))<0)
- {
- perror("bind");
- exit(3);
- }
- if(listen(socket_id,LISTENL)<0)
- {
- perror("listen");
- exit(4);
- }
- accpt_len= sizeof(struct sockaddr_in);
- while(1)
- {
- acc_res = accept(socket_id,(struct sockaddr *)&client_ad,&accpt_len);
- if(acc_res <0)
- {
- perror("1accept");
- exit(5);
- }
- printf("accept a new client ,the ip = %s\n",inet_ntoa(client_ad.sin_addr));
- if((pid=fork())==0){
- while(1){
- memset(buf,0,BUFSIZE);
- if((ret=recv(acc_res,buf,BUFSIZE,0))<0){
- perror("recv");
- exit(7);
- }
- buf[ret]=0;
- printf("buf = %s\n",buf);
- if(flag==USERNAME){
- user_id=find_name(buf);
- switch(user_id)
- {
- case -1:send_data(acc_res,"n\n");
- break;
- default:send_data(acc_res,"y\n");
- flag = USERPASS;
- }
- }
- else if( flag==USERPASS ){
- if(strcmp(users[user_id].userpass,buf)==0)
- {
- send_data(acc_res,"y\n");
- send_data(acc_res,"welcome login my cp server\n");
- printf("%s login\n",users[user_id].username);
- break;
- }else
- send_data(acc_res,"n\n");
- }
- }
-
- close(socket_id);
- close(acc_res);
- exit(0);
- }
- else
- close(acc_res);
- }
- return 0;
- }
- #include<stdio.h>
- #include<arpa/inet.h>
- #include<netinet/in.h>
- #include<sys/types.h>
- #include<sys/socket.h>
- #include<stdlib.h>
- #include<string.h>
- #define LEN 1024
- #define VALID 1
- #define INVALID 0
- int my_recv(int con, char buf[], int len)
- {
- int ll;
- ll = recv(con,buf,sizeof(buf),0);
- if(ll<0){
- perror("recv");
- exit(1);
- }
- return ll;
- }
- void input_mess(int con, const char *string)
- {
- char input_buf[32];
- char recv_buf[LEN];
- int flag_userinfo;
- do{
- printf("%s:",string);
- gets(input_buf);
- input_buf[strlen(input_buf)]=0;
- printf("%s:",input_buf);
- if(send(con,input_buf,strlen(input_buf),0)<0)
- {
- perror("send");
- exit(1);
- }
- if(my_recv(con,recv_buf,sizeof(recv_buf))<0)
- {
- perror("my_recv");
- exit(1);
- }
- printf("recv = %s\n",recv_buf);
- if(recv_buf[0]=='y')
- flag_userinfo = VALID;
- else
- flag_userinfo = INVALID;
- memset(recv_buf,0,sizeof(recv_buf));
- }while(flag_userinfo == INVALID);
- }
- int main(int argc, char *argv[])
- {
- int i,ret;
- int conn_fd,socketd;
- char recvbuf[LEN]={0};
- struct sockaddr_in serv_addr;
- if(argc!=5)
- {
- printf("the argc is not equals 5\n");
- return -1;
- }
- memset(recvbuf,0,LEN);
- memset(&serv_addr,0,sizeof(struct sockaddr_in));
- serv_addr.sin_family=AF_INET;
- for(i=0;i<argc;i++)
- {
- if(strcmp(argv[i],"-a")==0)
- {
- i++;
- if(inet_aton(argv[i],&serv_addr.sin_addr)==0){
- printf("invaild server ip address \n");
- exit(1);
- }/*如果该for中两个条件的判定是通过两个if链接的,那么要使用continue*/
- }
- else if(strcmp(argv[i],"-p")==0)
- {
- i++;
- int port = atoi(argv[i]);
- if(port<0||port>=65536) {
- printf("the port is overwiding\n");
- break;
- }else{
- serv_addr.sin_port = htons(port);
- }
- }
- }
- if(serv_addr.sin_addr.s_addr == 0||serv_addr.sin_port == 0)
- {
- printf("usage [-a] [address] [-p] [port]\n");
- exit(1);
- }
- socketd = socket(AF_INET,SOCK_STREAM,0);
- conn_fd = connect(socketd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr));
- if(conn_fd<0)
- {
- perror("connect");
- exit(1);
- }
- input_mess(socketd,"username");
- input_mess(socketd,"userpass");
- if((ret=my_recv(socketd,recvbuf,LEN))<0)
- {
- printf("data is too long");
- exit(1);
- }
- // recvbuf[ret]=0;
- printf("%s\n",recvbuf);
-
- return 0;
- }
六:编写程序遇到的问题
accept: Bad file descriptor---------------将accept创建的套接字在不合适的场合关了
connect: connected refused-------------connect的参数s有问题
阅读(1523) | 评论(0) | 转发(0) |