TCP下的套接字编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP下的套接字编程相关的知识,希望对你有一定的参考价值。

1.什么是套接字

     应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口
区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。Socket原意是“插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

      简单来说,套接字就是IP地址+端口号。用来标识网络中唯一的一个进程。

2.网络字节序列

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

地址。

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

3.socket地址的数据类型及相关函数

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,然而,各种网络协议的地址格式并不相同,如下图所示:

技术分享

常用第二种底层网络协议。

4.基于TCP下的套接字编程步骤

服务器端的步骤:

 1>创建套接字

    int socket(int domain,int type,int protocol)//domain:底层采用何种协议,AF_INET;type:什么传输类型,TCP面向字节流 SOCK_STREAM

2>定义数据结构,将网络信息添加进来

 struct sockaddr_in 

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

4>进行监听

   当listen状态的套接字不进行accept(),仍然可以连接,但系统会维护一个队列,只允许前面的几个请求可连接,当超过队列容量时,则不允许后来的进行连接。

5>调用accept()函数以阻塞方式来接收客户端的连接请求

6>接收消息

7>当客户端停止发消息时关闭连接

客户端步骤;

  对于客户端只是不需要进行绑定和监听,得到远端的信息直接进行相应的连接,连接成功后可以发送消息给服务器端。

5.相应代码实现:

  server.c
  1 #include<stdio.h>
  2 #include<sys/socket.h>
  3 #include<sys/types.h>
  4 #include<stdlib.h>
  5 #include<string.h>
  6 #include<arpa/inet.h>
  7 #include<netinet/in.h>
  8 #include<pthread.h>
  9 void* thread_run(void *arg)
 10 {
 11    int new_sock=(int)arg;
 12    char buf[1024];
 13     while(1)
 14     {
 15      memset(buf,‘\0‘,sizeof(buf));
 16      ssize_t size= read(new_sock,buf,sizeof(buf)-1);
 17      if(size>0)
 18      {
 19        buf[size]=‘\0‘;
 20        printf("client :%s\n",buf);
 22      }
 23      else if(size==0)
 24      {
 25       printf("client close....\n");
 26       exit(0);
 27       }
 28     }
 29     close(new_sock);
 30 
 31    return NULL;
 32   }
 33 void usage(char* proc)
 34 {
 35 
 36    printf("usage:%s [ip] [port]\n",proc);
 37 
 38 }
 39 int start(int port,char* ip)
 40 {
 41    int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 42    if(listen_sock<0)
 43    {
 44       printf("sock");
 45       exit(1);//zhongzhijincheng
 46    }
 47    //2.定义数据结构,添加网络信息
 48    struct sockaddr_in local;
 49    local.sin_family=AF_INET;
 50    local.sin_port=htons(port);
 51    local.sin_addr.s_addr=inet_addr(ip);
 52    socklen_t len=sizeof(local);
 53   //3.进行绑定
 54   if(bind(listen_sock,(struct sockaddr*)&local,len)<0)
 55    {
 56      printf("bind");
 57      exit(2);
 58 
 59    }
 60   //4.进行监听
 61    if(listen(listen_sock,5)<0)
 62     {
 63       printf("listen");
 64       exit(3);
 65     }
 66    return listen_sock;
 67 }
 71 int main(int argc, char* argv[])
 72 {
 73    if(argc!=3)
 74   {
 75      usage(argv[0]);
 76      return 1;
 77   }
 78    int port=atoi(argv[2]);//得到端口号
 79    //char*ip=argv[1];//得到IP
 80    //1.创建socket
 81    int sock=start(port,argv[1]);
 82 
 83    struct sockaddr_in client;
 84    socklen_t len=sizeof(client);
 85    while(1)
 86   {
 87      int new_fd=accept(sock,(struct sockaddr*)&client,&len);//接受连接请求
 88      if(new_fd<0)
 89      {
 90         printf("accept");
 91         continue;
 92       }
 93 #ifdef _V1_//单用户模式
 94      char buf[1024];
 95      while(1)
 96     {
 97      memset(buf,‘\0‘,sizeof(buf));
 98      ssize_t size= read(new_fd,buf,sizeof(buf)-1);
 99      if(size>0)
100      {
101        buf[size]=‘\0‘;
102        printf("client :%s\n",buf);
103     // fflush(stdout);
104      }
105      else if(size==0)
106      {
107       printf("client close....\n");
108       break;
109       }
110    close(new_fd);
111    // exit(0);
112     }
113 #elif _V2_//让子进程进行后面的数据接收
115 pid_t id=fork();
116 if(id<0)
117 {
118 
119    printf("fork");
120    exit(3);
121 
122 }
123 else  if(id==0)
124 {
125   close(sock);
126   char buf[1024];
127     while(1)
128     {
129      memset(buf,‘\0‘,sizeof(buf));
130      ssize_t size= read(new_fd,buf,sizeof(buf)-1);
131      if(size>0)
132      {
133      buf[size]=‘\0‘;
134      printf("client :%s\n",buf);
135 
136      }
137      else if(size==0)
138      {
139       printf("client close....\n");
140       break;
141 
142     }
143     }
144   close(new_fd);
145   exit(0);  
146 }
147 else
148 {
149    close(new_fd);
150 }
151 #elif _V3_//让一个线程去完成后面的数据传送
152  pthread_t tid;
153 
154  if(pthread_create(&tid,NULL,tnread_run,(void*)new_fd)<0);
155 {
156 
157 
158 printf("pthread_create");
159 }
160  pthread_detach(tid);
161 #else
162  printf("default");
163 #endif
164 
165   }
166 
167     return 0;
168 
169 }


client.c
  
  9 void usage(char *proc)
 10 {
 11 
 12   printf("usage : %s [ip][port]\n",proc);
 13 
 14 }
 15 
 16 
 17 int main(int argc, char *argv[])
 18 {
 19    if(argc!=3)
 20    {
 21       usage(argv[0]);
 22       return 1;
 23    }
 24   int sock=socket(AF_INET,SOCK_STREAM,0);
 25   if(sock<0)
 26   {
 27    printf("socket");
 28    exit(1);
 29   }
 30   int port=atoi(argv[2]);
 31   char* ip=argv[1];
 32   struct sockaddr_in  remote;//得到远端信息
 33    remote.sin_family=AF_INET;
 34    remote.sin_port=htons(port);
 35    remote.sin_addr.s_addr=inet_addr(ip);
 36    int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));//建立连接
 37    if(ret<0)
 38   {
 39      printf("conect");
 40   }
 41    char buf[1024];
 42    while(1)
 43    {
 44      printf("please enter:    ");
 45      scanf("%s",buf);
 46      write(sock,buf,sizeof(buf));
 47      fflush(stdin);
 48    }
 49    return 0;
 50 }

总结:利用套接字实现了TCP协议的三次握手机制,从而进行服务器端和客户端的数据传输,但是只能进行单方面的通信,客户端只能发送消息给服务器端,服务器端接受消息并显示,而不能给客户端发消息。




本文出自 “输出菱形图案” 博客,请务必保留此出处http://10541571.blog.51cto.com/10531571/1782685

以上是关于TCP下的套接字编程的主要内容,如果未能解决你的问题,请参考以下文章

C/C++ 网络编程4: 基本TCP套接字编程

TCP,UDP协议下的socket通信

TCP/IP网络编程:02套接字类型与协议设置

第4章 基本tcp套接字编程

TCP/IP网络编程之套接字类型与协议设置

网络编程套接字