1. 程式人生 > >linux網路程式設計之伺服器

linux網路程式設計之伺服器

基於tcp協議的網路程式

1.所用函式:

  • socket函式
    這裡寫圖片描述

    • socket()開啟一個網路埠,如果成功,就像open()一樣返回一個檔案描述符,應用程式可以像讀寫檔案一樣用read/write在網路上首發資料,如果調用出錯返回-1
  • bind函式:
    這裡寫圖片描述

    • 伺服器程式所監聽的網路地址和埠號通常是固定不變得,客戶端程式得知伺服器程式的地址和埠後就可以向伺服器發起連線,因此需要呼叫bind()繫結一個固定的網路地址和埠號`.bind函式的作用是將引數sockfd和myaddr繫結在一起,使sockfd這個用於網路通訊的檔案描述符監聽myaddr所描述的地址和埠號。
    • bind()成功是返回0,失敗返回-1
  • listen()函式
    這裡寫圖片描述

    • listen()函式的作用是將套接字的狀態設定為監聽狀態,即檢測新的客戶是否到來的狀態
  • accept()函式
    這裡寫圖片描述

  • connect()函式

    • 客戶端需要呼叫connect()連線伺服器,connect()bind()的引數形式一致,區別在於bind的引數是自己的地址,而connect的引數是對方的地址
    • 成功返回0,失敗返回-1
  • 由於本節基於IPv4的socket網路程式設計,sockaddr_in中的成員struct in_addr sin_addr表示32位的IP地址。但是我們通常用點分十進位制的字串表示IP地址,以下函式可以在字串表示和in _addr表示之間轉換。

    • 字串轉in_addr
      這裡寫圖片描述

    • in_addr轉字串
      這裡寫圖片描述

2.tcp_server.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
#include <netinet/in.h>

static void usage(const char* proc)
{
    printf("Usage:%s [local_ip] [local_port]\n"
,proc); } int startup(const char* _ip,int _port) { int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0 ) { perror("socket"); exit(2); } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = inet_addr(_ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(3); } if(listen(sock,10) < 0) { perror("listen"); exit(4); } return sock; } //./tcp_server ip port int main(int argc,char* argv[] ) { if(argc!=3) { usage(argv[0]); return 1; } while(1) { struct sockaddr_in client; socklen_t len = sizeof(client); int listen_sock = startup(argv[1],atoi(argv[2])); int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len); if(new_sock<0) { perror("acc"); continue; } printf("get a new client ,%s:%d\n",inet_ntoa(client.sin_addr),\ ntohs(client.sin_port)); while(1) { char buf[1024]; ssize_t s= read(new_sock,buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client: %s\n",buf); write(new_sock,buf,strlen(buf)); } else if(s==0) { close(new_sock); printf("client is quit\n"); break; } else { perror("read"); exit(5); } } } }

3.tcp_client.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>


static void usage(const char* proc)
{
    printf("Usage:%s [local_ip] [local_port]\n",proc);
}
//tcp_client server_ip server_port
int main(int argc,char* argv[])
{

    if(argc!=3)
    {
        usage(argv[0]);
        return 1;
    }
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0 )
    {
        perror("socket");
        exit(2);
    }
    struct sockaddr_in server_sock;
    server_sock.sin_family = AF_INET;
    server_sock.sin_port = htons(atoi(argv[2]));
    server_sock.sin_addr.s_addr = inet_addr(argv[1]);

    if(connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock))<0)
    {
        printf("connect failed ");
        exit(3);
    }
    printf("connect success\n");


    char  buf[1024];
    while(1)
    {
        printf("Please Enter#");
        fflush(stdout);
        ssize_t s=read(0,buf,sizeof(buf)-1);
        if(s>0)
        {
            buf[s-1]=0;
            write(sock,buf,strlen(buf));
            s = read(sock,buf,sizeof(buf)-1);
            if(s>0)
            {
                buf[s] = 0;
                printf("server ehco:%s\n ",buf);
            }
        }
    }
}

執行:

  • 輸入指令 >ifconfig 檢視本機的ip地址為下圖:
    這裡寫圖片描述
  • 輸入>./tcp_server.c 192.168.1.103 8080 執行伺服器端。
  • 同時再開一個終端輸入> >./tcp_client.c 192.168.1.103 8080 執行客戶端。
  • 接下來在客戶端給伺服器端發訊息,同時從客戶端可以收到來自伺服器端的迴應,如下圖:
    這裡寫圖片描述
    這裡寫圖片描述