基於TCP的客戶端、服務器端socket編程


 一.實驗目的

理解tcp傳輸客戶端服務器端通信流程

二.實驗平台

MAC OS

三.實驗內容

編寫TCP服務器套接字程序,程序運行時服務器等待客戶的連接,一旦連接成功,則顯示客戶的IP地址、端口號,並向客戶端發送字符串。 

四.實驗原理

使用TCP套接字編程可以實現基於TCP/IP協議的面向連接的通信,它分為服務器端和客戶端兩部分,其主要實現過程如下

 

四.實驗流程

服務器端流程

1.創建socket

  socket是一個結構體,被創建在內核中

     sockfd=socket(AF_INET,SOCK_STREAM,0);   //AF_INT:ipv4, SOCK_STREAM:tcp協議

2.調用bind函數

  將socket和地址(包括ip、port)綁定。

  需要定義一個結構體地址,以便於將port的主機字節序轉化成網絡字節序

    struct sockaddr_in serveraddr;    //地址結構體

  bind函數

     bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))

3.listen監聽,將接收到的客戶端連接放入隊列

    listen(sockfd,10)  //第二個參數是隊列長度

4.調用accept函數,從隊列獲取請求,返回socket描述符

  如果無請求,將會阻塞,直到獲得鏈接

    int fd=accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);

5.調用IO函數和客戶端雙向通信

6.關閉accept返回的socket

    close(fd);

 

服務器端代碼:

  1 #include "iostream"
  2 #include "netdb.h"
  3 #include "stdio.h"
  4 #include "stdlib.h"
  5 #include "sys/socket.h"
  6 #include "unistd.h"
  7 #include "arpa/inet.h"
  8 #include "string.h"
  9 #include "memory.h"
 10 #include "signal.h"
 11 #include "time.h"
 12 
 13 int sockfd;
 14 
 15 void sig_handler(int signo)
 16 {
 17     if(signo==SIGINT)
 18     {
 19         printf("Server close \n");
 20         close(sockfd);
 21         exit(1);
 22     }
 23 }
 24 
 25 //輸出連接上來的客戶端相關信息
 26 void out_addr(struct sockaddr_in *clientaddr)
 27 {
 28     //將端口從網絡字節序轉成主機字節序
 29     int port =ntohs(clientaddr->sin_port);    
 30     char ip[16];
 31     memset (ip,0,sizeof(ip));
 32     inet_ntop(AF_INET,
 33             &clientaddr->sin_addr.s_addr,ip,sizeof(ip));
 34     printf("client:%s(%d)connected\n",ip,port);
 35 }
 36 
 37 void do_service(int fd)
 38 {
 39     //獲取系統時間
 40     long t=time(0);
 41     char *s=ctime(&t);
 42     size_t size=strlen(s)*sizeof(char);
 43     //將服務器端的系統時間寫到客戶端
 44     if(write(fd,s,size)!=size)
 45     {
 46         perror("write error");
 47     }
 48 }
 49 
 50 int main(int argc,char *argv[])
 51 {
 52     if(argc<2)
 53     {
 54         printf("usage:%s #port\n",argv[0]);
 55         exit(1);
 56     }
 57 
 58     if(signal(SIGINT,sig_handler)==SIG_ERR)
 59     {
 60         perror("signal sigint error");
 61         exit(1);
 62     }
 63     
 64     /*1. 創建socket
 65      AF_INT:ipv4
 66      SOCK_STREAM:tcp協議
 67     */
 68     sockfd=socket(AF_INET,SOCK_STREAM,0);
 69     if(sockfd<0){
 70         perror("socket error");
 71         exit(1);    
 72     }
 73 
 74     /*2:調用bind函數綁定socket和地址*/
 75 
 76     struct sockaddr_in serveraddr;
 77     memset(&serveraddr,0,sizeof(serveraddr));
 78     //往地址中填入ip,port,internet類型
 79     serveraddr.sin_family=AF_INET;  //ipv4
 80     serveraddr.sin_port=htons(atoi(argv[1]));  //htons主機字節序轉成網絡字節序
 81 
 82     serveraddr.sin_addr.s_addr=INADDR_ANY;
 83 
 84     if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
 85     {
 86         perror("bind error");
 87         exit(1);
 88         
 89     }
 90 
 91     /*3:調用listen函數監聽(指定port監聽)
 92     通知操作系統區接受來自客戶頓的連接請求
 93     第二個參數:指定隊列長度
 94     */
 95     
 96     if(listen(sockfd,10)<0)
 97     {
 98         perror("listen error");
 99     
100     }
101 
102     /*4:調用accept函數從隊列中獲得一個客戶端的請求連接
103     */
104     
105     struct sockaddr_in clientaddr;
106     socklen_t clientaddr_len=sizeof(clientaddr);
107 
108     while(1){
109         int fd=accept(sockfd,
110                 (struct sockaddr*)&clientaddr,
111                   &clientaddr_len);
112         if(fd<0){
113             perror("accept error");
114             continue;
115         }
116 
117         /*5:調用IO函數(read/write)和
118             連接的客戶端進行雙向通信
119         */
120         out_addr(&clientaddr);
121         do_service(fd);
122 
123         /*6.關閉socket*/
124         close(fd);
125     }
126 
127     return 0;
128 }

 

客戶端代碼:

 1 #include "netdb.h"
 2 #include "sys/socket.h"
 3 #include "stdio.h"
 4 #include "stdlib.h"
 5 #include "string.h"
 6 #include "memory.h"
 7 #include "unistd.h"
 8 #include <arpa/inet.h>
 9 
10 int main(int argc,char *argv[])
11 {
12     if(argc<3)
13     {
14         printf("usage:%s ip port \n",argv[0]);
15         exit(1);          
16     }
17    
18     /*步驟1:創建socket*/
19     int sockfd=socket(AF_INET,SOCK_STREAM,0);
20     if(sockfd<0)
21     {
22         perror("socket error");
23         exit(1);
24     }    
25 
26     struct sockaddr_in serveraddr;
27     memset(&serveraddr,0,sizeof(serveraddr));
28     serveraddr.sin_family=AF_INET;
29     serveraddr.sin_port=htons(atoi(argv[2]));
30 
31     //主機字節序轉換成網絡字節序
32     inet_pton(AF_INET,argv[1],
33             &serveraddr.sin_addr.s_addr);
34    
35     /*步驟2:客戶端調用connect函數連接到服務器
36    
37     */
38     if(connect(sockfd,(struct sockaddr*)&serveraddr,
39                 sizeof(serveraddr))<0)
40     {
41         perror("connect error");
42         exit(1);
43     }
44 
45     /*步驟3:調用IO函數(read/write)和服務器端雙向通信*/
46     char buffer[1024];
47     memset(buffer,0,sizeof(buffer));
48     size_t size;
49 
50     if((size=read(sockfd,
51                     buffer,sizeof(buffer)))<0)
52     {
53         perror("read error");
54     }
55 
56     if(write(STDOUT_FILENO,buffer,size)!=size)
57     {
58         perror("write error");
59     }
60 }

 

 實驗結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM