1. 程式人生 > >linux網路程式設計--TCP/IP協議

linux網路程式設計--TCP/IP協議

特點

  1. TCP協議的位於資料傳輸層,其上一層是應用層,因此其目的是為了實現一個應用於另一個應用之間資料傳輸。

  2. TCP協議需要進行三次握手實現資料傳送和接收的同步。

    第一次握手:客戶端向服務端提出連線請求。這時TCP SYN標 志置位。客戶端告訴服務端序列號區域合法,需要檢查。客戶端 在TCP報頭的序列號區中插入自己的ISN。服務端收到該TCP分 段後,。
    第二次握手:接收主機通過發回具有以下專案的資料段表示回 復:同步標誌置位、即將傳送的資料段的起始位元組的順序號、應 答並帶有將收到的下一個資料段的位元組順序號
    第三次握手:客戶端確認收到服務端的ISN(ACK標誌置位)。到此為止建立完整的TCP連線,開始全雙工模式的資料傳輸過程。

實現過程

1.客戶端程式

#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#define BUF_SIZE 512
/**********************所用到的函式*******************************
int socket(int domain, int type, int protocol);  
建立套接字函式
AF_INET  IPV4協議   SOCK_STREAM 流套接字
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
結構體sockaddr的成員
 struct sockaddr {
           sa_family_t sa_family;
           char        sa_data[14];
 }
struct sockaddr_in {
           sa_family_t    sin_family; /* address family: AF_INET 
           in_port_t      sin_port;   /* port in network byte order
           struct in_addr sin_addr;   /* internet address 
       };
struct in_addr {
           uint32_t       s_addr;     /* address in network byte order 
       };

   int listen(int sockfd, int backlog);
   sighandler_t signal(int signum, sighandler_t handler);
   int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
   int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
   char *fgets(char *s, int size, FILE *stream);//接收終端輸入檔案流
    ********************************************************/
int main()
{
int client_id;
struct sockaddr_in clientadd;
char buffer[BUF_SIZE];
client_id=socket(AF_INET,SOCK_STREAM,0);  //建立套接字
clientadd.sin_family=AF_INET;   //結構體成員賦值
clientadd.sin_port=htons(9736);//指定埠號
clientadd.sin_addr.s_addr=inet_addr("192.168.1.121"); //繫結IP地址,此處的IP為伺服器IP
if(connect(client_id,(struct sockaddr *)&clientadd,sizeof(clientadd))==-1)//建立連線
{
    //連結失敗
    printf("connect   failed!\n");
    exit(EXIT_FAILURE);
}
printf("please input:");
fgets(buffer,BUF_SIZE,stdin);
//向伺服器寫
write(client_id,buffer,BUF_SIZE);//將獲取的資料傳送至緩衝區
sleep(rand()%3);
memset(buffer,0,strlen(buffer));
read(client_id,buffer,BUF_SIZE);//接收返回資料
printf("You input:%s\n",buffer);
close(client_id);
return 0;
}

2.伺服器程式

伺服器程式主要實現從客戶端接收資料,將接收到的資料返回給客戶端。

#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#define BUF_SIZE 512
/********用到的函式************************
int socket(int domain, int type, int protocol);  建立套接字
AF_INET  IPV4協議   SOCK_STREAM
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
   struct sockaddr {
           sa_family_t sa_family;
           char        sa_data[14];
       }
   struct sockaddr_in {
           sa_family_t    sin_family; /* address family: AF_INET 
           in_port_t      sin_port;   /* port in network byte order
           struct in_addr sin_addr;   /* internet address 
       };
   struct in_addr {
           uint32_t       s_addr;     /* address in network byte order 
       };
   int listen(int sockfd, int backlog);
   sighandler_t signal(int signum, sighandler_t handler);

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

int main()
{

int socket_id,client_id;
struct sockaddr_in serveradd;
struct sockaddr_in clientadd;
int clientlen;
char buffer[BUF_SIZE+1];
socket_id=socket(AF_INET,SOCK_STREAM,0);  //建立套接字
serveradd.sin_family=AF_INET;
serveradd.sin_port=htons(9736);//指定埠好
serveradd.sin_addr.s_addr=htonl(INADDR_ANY); //繫結IP地址    這裡指定監聽的IP地址是任何一個訪問的IP
if(bind(socket_id,(struct sockaddr *)&serveradd,sizeof(serveradd))==-1)
{
    //繫結失敗
    printf("connect   failed!\n");
    exit(EXIT_FAILURE);
}
//伺服器端需要繫結埠和IP,伺服器端需要對固定的埠和指定的IP進行監聽,因此需要進行bind操作,而客戶端部分不需要
listen(socket_id,5);//最大允許5個客戶端訪問
signal(SIGCHLD,SIG_IGN);
while(1)
{
    clientlen=sizeof(clientadd);
    printf("please waiting....\n");
    client_id=accept(socket_id,(struct sockaddr *)&clientadd,&clientlen);//監聽zijincheng
    if(fork()==0)//新建一個子程序,在子程序中實現接收客戶端傳送過來的內容並將其傳送回去,同時顯示在終端上。
    {
        read(client_id,buffer,BUF_SIZE);
        buffer[BUF_SIZE]='\0';
        printf("You input :%s\n",buffer);
        sleep(rand()%3);
        write(client_id,buffer,BUF_SIZE);
        close(client_id);
        exit(EXIT_SUCCESS);
    }
    else
    {
        close(client_id);//關閉子程序
    }
}
}