TCP之socket编程

socket(套接字):IP地址+端口号,唯一标识网络中的一个进程

socket编程中建立连接的两个进程都有一个socket来标识唯一一个连接。

网络字节序:网络数据流有大小端之分,发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,网络数据流的地址规定:先发出的数据是低地址,后发出的数据是

地址。 

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。

例:如果端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8, 也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位端口号被解释成0xe803,不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的, 接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。

服务器端socket:

1.创建套接字:int socket(int domain,int type,int protocol) //domain底层采用何种协议,传输类型,TCP面向字节流式

2.使用struct socketaddr_in 结构体填充网络方面信息

3.绑定:将套接字信息填充到内核中

4.设置套接字状态为监听状态,接收客户端发来的连接请求

5.等待客户请求,当请求连接来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)

6.新的套接字和客户端进行通信

accept函数:在一个套接口接受一个连接。

int accept(int sockfd,struct sockaddr*addr,socklen_t* addrlen)

 sockfd和 listen() 中套接字描述符相同。addr要求接入的信息所要去的地方。返回值:如果执行成功,返回值为0,否则设置错误码,返回-1。


bind函数:将一本地地址与一套接口捆绑。

int bind(int sockfd, const struct sockaddr* addr, socklen_t len);

适用于未连接的数据报或流类套接口,在connect()listen()调用前使用。当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号

服务器端代码:

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 #include<pthread.h>
  9 int start(int _port,char* ip)
 10 {   
 11     //1.create sock
 12     int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 13     if(listen_sock < 0){
 14         perror("sock");
 15         exit(1);
 16     }
 17     //2.fill information 
 18     struct sockaddr_in local;
 19     local.sin_family=AF_INET;
 20     local.sin_port=htons(_port);
 21     local.sin_addr.s_addr=inet_addr(ip);
 22     //3.bind
 23     if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
 24     {
 25         perror("bind");
 26         exit(2);
 27     }
 28     //4.set listen 
 29     if(listen(listen_sock,5)<0)
 30     {
 31         perror("listen");
 32         exit(3);
 33     }
 34     return listen_sock;
 35 
 36    
 37 }
 38 void usage(const char *proc)
 39 {   
 40     printf("usage:%s [ip] [port]\n",proc);
 41 }
 42 
 43 void* thread_run(void* arg)
 44 {
 45     int sock =(int)arg;
 46     char buf[1024];
 47     while(1)
 48     {
 49         memset(buf,'\0',sizeof(buf));
 50         ssize_t _size=read(sock,buf,sizeof(buf)-1);
 51         if(_size<0)
 52         {
 53             printf("read fail...\n");
 54             exit(1);
 55         }else if(_size==0)
 56         {
 57             printf("closed connect...\n");
 58             exit(2);
 59         }else
 60         {
 61             printf("client# %s\n",buf);
 62         }
 63     }
 64 }
 65 
 66 int main(int argc,char* argv[])
 67 {
 68     if(argc!=3)
 69     {
 70         usage(argv[0]);
 71         exit(1);
 72     }
 73     int listen_sock=start(atoi(argv[2]),argv[1]);
 74     struct sockaddr_in client;
 75     socklen_t len=sizeof(client);
 76     int done=0;
 77     while(!done)
 78     {
 79         int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
 80         if(new_sock<0)
 81         {
 82             perror("accept");
 83             continue;
 84         }
 85         printf("get a connect... [sock]:%d [ip]:%s [port]:%d\n",new_sock,inet_ntoa(cl ient.sin_addr),ntohs(client.sin_port));
 86    
 87 #ifdef _V1_
 88         while(1)
 89         {
  90             char buf[1024];
 91             memset(buf,'\0',sizeof(buf));
 92             ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
 93             if(_size<0)
 94             {
 95                 printf("read fail...\n");
 96                 exit(1);
 97             }else if(_size==0)
 98             {
 99                 printf("closed connect...\n");
100                 exit(2);
101             }else
102             {
103                 printf("client# %s",buf);
104             }
105         }
106     }
107 #elif _V2_
108         pid_t id=fork();
109         if(id<0)
110         {
111             printf("create fail...\n");
112             exit(3);
113         }else if(id==0)
114         {
115             close(listen_sock);//close listen_sock,only deal with I/Ostream
116             while(1)
117             {
118                 char buf[1024];
119                 memset(buf,'\0',sizeof(buf));
120                 ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
121                 if(_size<0)
121                 if(_size<0)
122                 {
123                     printf("read fail...\n");
124                     exit(1);
125                 }else if(_size==0)
126                 {
127                     printf("closed connect...\n");
128                     exit(2);
129                 }else
130                 {
131                     printf("client# %s\n",buf);
132                 }
133             }
134             close(new_sock);
135         }else
136         {
137             close(new_sock);
138         }
139     }
140 
141 #elif _V3_
142         pthread_t tid;
143         if(tid=pthread_create(&tid,NULL,thread_run,(void*) new_sock)<0)
144         {
145             perror("pthread_create");
146             exit(2);
147         }
148         pthread_detach(tid);
149     }
150 #else
151     printf("default\n");
152     }
153 #endif 
154    return 0;
155 }


connect函数:

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

向服务器端发送连接请求,只维护一个连接,连接成功后通过sock进行传输
客户端:

1.创建套接字(进行三次握手)

2.向服务器发连接请求

3.传输数据

4.关闭套接字(四次挥手,即释放链接)

客户端代码:

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 
  9 void usage(char* proc)
 10 {
 11     printf("usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 int main(int argc,char*argv[])
 14 {
 15     if(argc!=3)
 16     {
 17         usage(argv[0]);
 18         exit(1);
 19     }
 20     char* remote_ip=argv[1];
 21     int remote_port=atoi(argv[2]);
 22     int sock=socket(AF_INET,SOCK_STREAM,0);
 23     if(sock < 0)
 24     {
 25         perror("socket");
 26         exit(2);
 27     }
 28     struct sockaddr_in remote;
 29     remote.sin_family=AF_INET;
 30     remote.sin_port=htons(remote_port);
 31     remote.sin_addr.s_addr=inet_addr(remote_ip);
 32     //send SYN head
 33     if(connect(sock,(struct sockaddr*)&remote,sizeof(remote))<0)
 34     {
 35         perror("connect");
 36         exit(3);
 37     }
 38     char msg[1024];
 39     while(1)
 40     {
 41         memset(msg,'\0',sizeof(msg));
 42         printf("please input msg:");
 43         fflush(stdout);
 44         if(read(0,msg,sizeof(msg))>0){
 45             write(sock,msg,strlen(msg));
 46         }
 47    
 48     }
 49     return 0;
 50 }


运行结果:

单用户:

wKioL1dAHu_ScCVyAABP5B4g630041.png



利用线程模拟多用户:

wKiom1dAHabhO-hTAABgFQiFju8234.png



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章