1. 程式人生 > >linux socke程式設計例項:一個簡單的echo伺服器程式

linux socke程式設計例項:一個簡單的echo伺服器程式

    也許是第一次真正使用linux作業系統,忽然對丟棄已久的C產生了很大的興趣,最近想學點linux的知識,在linux的世界裡面,接觸得最多的還是C,故有感寫一下linux的socket程式。
    也許很多朋友會像我一樣,這樣的程式在Java寫得太多,以至對Socket的通訊細節還不曾忘懷。由於未有linux下
程式設計經驗,在寫程式過程中碰到很多不懂的東西,經過google一翻後,終於把一些基本的東西搞懂了。好了,閒話少講,下面說說程式設計的想法。
    本文編的是echo伺服器示例程式,當收到客戶端的資料,伺服器把資料不經加工地傳送給客戶。採用TCP連線,採用埠8080進行設計,在整個過程中主要涉及socket的通訊。

首先建立一個 socket,程式碼如下:
int socketfd;
socketfd 
= socket(AF_INET, SOCK_STREAM, 0);

 socket函式是我們寫socket程式遇到的第一個函式,它在指定的協議上建立一個socket,它的函式說明如下所示:

#include <sys/socket.h>
int socket ( int AddressFamily,  int Type, int  Protocol)


其中:AddressFamily引數指定socket操作中所要解釋的網路地址型別,值為如下之一:
AF_UNIX
表示作業系統檔案路徑
AF_INET
表示Internet網路地址
AF_NS
表示XEROX網路地址
Type引數表明了通訊的語義,即通訊連線的方式。引數為如下之一:
SOCK_STREAM
提供穩定可靠的連線,並且是雙向的通訊方式,如TCP。
SOCK_DGRAM
提供無連線的資料報通訊,如UDP。
SOCK_RAW
提供該問內部網路協議和網路介面, 只有root使用者才可以使用些協議。

返回值:成功則返socket描述符,出錯則返回-1,可通過errno程式碼進行檢視錯誤原因。


再次,把socket繫結到本機上,程式碼如下:
struct sockaddr_in sa;
    bzero(
&sa, sizeof(sa));
    sa.sin_family 
= AF_INET;
    sa.sin_port 
= htons(EHCO_PORT);
    sa.sin_addr.s_addr 
= htons(INADDR_ANY);
    bzero(
&(sa.sin_zero), 8);

    
if(bind(socketfd, (struct sockaddr *)&sa, sizeof(sa))!=0)
    {
        printf(
"bind failed ");
        printf(
"errno=%d ", errno);
        exit(
1);
    }
    
else
    {
        printf(
"bind successfully ");
    }

上面的程式碼中,定義一個scokaddr_in 結構體變數sa,然後填機服務所要開通的埠號和地址。
 sa.sin_family = AF_INET;
 >表明地址型別
 sa.sin_port 
= htons(EHCO_PORT);
>埠號為8080
    sa.sin_addr.s_addr 
= htons(INADDR_ANY);
 >表明繫結在本機

  然後利用bind函式,把剛才已建立的socket作為引數,繫結起來。

繫結完成後,伺服器要偵聽客戶端的連線,因此首先要完成偵聽設定這一過程,由listen函式實現,程式碼如下:
if(listen(socketfd ,MAX_CLIENT_NUM) !=0)
    
{
        printf(
"listen error ");
        exit(
1);
    }

    
else
    
{
        printf(
"listen successfully ");
    }

 listen(socketfd, MAX_CLIENT_NUM)表明在socketfd上偵聽,其中客戶個數最大值為MAX_CLIENT_NUM。

完成偵聽後,可以讓客戶與伺服器進行連線了。服務想獲得客戶的請求,則需要通過 accept函式來獲得。同時,需要採用一個sockaddr_in結構體來獲得客戶的資訊。程式碼如下:
    int clientfd;  
    
struct sockaddr_in clientAdd;
    
char buff[101];
    socklen_t len 
=sizeof(clientAdd);
    
int closing =0;
    
while( closing ==0&& (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 )
    {
        
int n;
        
while((n = recv(clientfd,buff, 100,0 )) >0)
        {
            printf(
"number of receive bytes = %d ", n);
            write(STDOUT_FILENO, buff, n);
            send(clientfd, buff, n, 
0);
            buff[n] 
='';
            
if(strcmp(buff, "quit "==0)
            {
                
break;
            }
            
elseif(strcmp(buff, "close "==0)
            {
                
//server closing                closing =1;
                printf(
"server is closing ");
                
break;
            }
        }

        close(clientfd);
    }

其中clientfd為客戶的socket,在伺服器端,每接受一個客戶連線,都會返回一個客戶的socket描述符,伺服器根據它與客戶進行通訊。clientAdd為客戶地址資訊的結構體,在accept函式中完成對它的填充,可依此得到客戶的地址資訊。

while( closing ==0&& (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 )
等待第一個客戶,當第一個客戶的請求來到伺服器後,該函式會返回,clientfd為客戶的socket描述符。
接著進行通訊
while((n = recv(clientfd,buff, 100,0 )) >0)
等待客戶的資料,收到資料後,在標準輸入出顯示接收的資料資訊,並把它傳送回給客戶:send(clientfd, buff, n, 0);
在這裡,我們採用簡單的命令對通訊進行控制,quit表示客戶要結束通訊過程,而 close表示客戶請求關閉伺服器。關閉只需使用 close函式即可完成。

下面是完整的程式碼:
#include <netdb.h>
#include 
<sys/socket.h>
#include 
<errno.h>
#include 
<stdio.h>
#include 
<unistd.h>#define EHCO_PORT    8080#define MAX_CLIENT_NUM        10int main()
{
    
int socketfd;
    socketfd 
= socket(AF_INET, SOCK_STREAM, 0);
       
    
if(socketfd ==-1)
    {
        printf(
"errno=%d ", errno);
        exit(
1);
    }
    
else
    {
        printf(
"socket create successfully ");
    }

    
struct sockaddr_in sa;
    bzero(
&sa, sizeof(sa));
    sa.sin_family 
= AF_INET;
    sa.sin_port 
= htons(EHCO_PORT);
    sa.sin_addr.s_addr 
= htons(INADDR_ANY);
    bzero(
&(sa.sin_zero), 8);

    
if(bind(socketfd, (struct sockaddr *)&sa, sizeof(sa))!=0)
    {
        printf(
"bind failed ");
        printf(
"errno=%d ", errno);
        exit(
1);
    }
    
else
    {
        printf(
"bind successfully ");
    }

    
//listenif(listen(socketfd ,MAX_CLIENT_NUM) !=0)
    {
        printf(
"listen error ");
        exit(
1);
    }
    
else
    {
        printf(
"listen successfully ");
    }

    
int clientfd;
    
struct sockaddr_in clientAdd;
    
char buff[101];
    socklen_t len 
=sizeof(clientAdd);
    
int closing =0;
    
while( closing ==0&& (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 )
    {
        
int n;
        
while((n = recv(clientfd,buff, 100,0 )) >0)
        {
            printf(
"number of receive bytes = %d ", n);
            write(STDOUT_FILENO, buff, n);
            send(clientfd, buff, n, 
0);
            buff[n] 
='';
            
if(strcmp(buff, "quit "==0)
            {
                
break;
            }
            
elseif(strcmp(buff, "close "==0)
            {
                
//server closing                closing =1;
                printf(
"server is closing ");
                
break;
            }
        }

        close(clientfd);
    }

    close(socketfd);

    
return0;
}


    經過cc編譯後,即可執行。在這裡我們寫的程式是伺服器程式,要想完成通訊,也得寫一個客戶端程吧???
    呵呵,我們先把客戶端的程式放下來,先測測我們伺服器程式吧。在這裡,我們使用 telnet充當客戶端進行測試,telnet可以說是一個很好的客戶端程式。呵呵:
本機IP為192.168.0.69,整個通訊過程如下:

[email protected]:~$ telnet 192.168.0.698080
Trying 
192.168.0.69...
Connected to 
192.168.0.69.
Escape character 
is'^]'.
hello
! This is my first packet.Can you reply to me?
hello
! This is my first packet.Can you reply to me?
Ohh, U did it
!
Ohh, U did it
!
see U next time
!!!
see U next time
!!!
quit
quit
Connection closed by foreign host.
[email protected]:
~$ telnet 192.168.0.698080
Trying 
192.168.0.69...
Connected to 
192.168.0.69.
Escape character 
is'^]'.
close
close
Connection closed by foreign host.

上面連線了兩次,第一次時,與伺服器通訊3次,每次發信息過去後,都收到與發出來一模一樣的資訊。當用戶輸入quit的時候,服務端就會關閒與客戶通訊的socket,通訊結束。第二次客戶只輸入close,伺服器響應後馬上關閉伺服器,同時也關閉客戶端。下面是伺服器的顯示內容:
[email protected]:~/program/c$ ./echoServer
socket create successfully
bind successfully
listen successfully
//第一次通訊
number of receive bytes 
=53
hello
! This is my first packet.Can you reply to me?
number of receive bytes 
=16
Ohh, U did it
!
number of receive bytes 
=20
see U next time
!!!
number of receive bytes 
=6
quit
//第二次通訊
number of receive bytes 
=7
close
server 
is closing

當客戶端輸入quit時,只是客戶端關閉,伺服器還接著為其它客服端服務。當客戶端輸入 close時,服務關閉。

當前出現的問題:
    我們的伺服器序程只能與一個客戶端進行通訊,只能當客戶端發出quit命令關閉後才能與下一個客戶端通訊。

如何解決:等待下一篇文章和大家分析一下解決方法。

相關推薦

linux socke程式設計例項一個簡單echo伺服器程式

    也許是第一次真正使用linux作業系統,忽然對丟棄已久的C產生了很大的興趣,最近想學點linux的知識,在linux的世界裡面,接觸得最多的還是C,故有感寫一下linux的socket程式。    也許很多朋友會像我一樣,這樣的程式在Java寫得太多,以至對Socke

Linux網路程式設計(一)一個簡單的socket程式

伺服器: /* *tcp_server.c */ #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include

socket例項C語言一個簡單的聊天程式

我們老師讓寫一個簡單的聊天軟體,並且實現不同機子之間的通訊,我用的是SOCKET程式設計。不廢話多說了,先附上程式碼: 伺服器端server.c #include <stdio.h> #include <stdlib.h> #include

Win32 程式開發一個簡單的Win32程式

1)什麼是Win32 Win32是指Microsoft Windows作業系統的32位環境,與Win64 都為Windows常見環境。如今的Win32作業系統可以一邊聽音樂,一邊程式設計,一邊列印文件。Win32作業系統是一個典型的多執行緒作業系統。(摘抄自百度百科)

Linux C程式設計一站式學習程式設計練習實現簡單的Shell

Linux C程式設計一站式學習P585程式設計練習: 實現簡單的Shell 用講過的各種C函式實現一個簡單的互動式Shell,要求: 給出提示符,讓使用者輸入一行命令,識別程式名和引數並呼叫適當的exec函式執行程式,待執行完成後再次給出提示符。 識別和處理

R in Action學習筆記一個簡單的資料處理例項

這是來自《R in Action》中的一個數據處理例項。 資料:一組學生的名字和其對應的數學、科學、英語的成績; 資料分析需求: 1、為所有學生確定一個單一的成績衡量指標; 2、將前20%的學生評定為A,接下來20%的學生評定為B,依次類推; 3、按照學生姓氏的字母順序對學生排序。

Linux網絡編程(一)一個簡單的socket程序

服務 htonl 網絡 pre fin efi from ret span 服務器: /* *tcp_server.c */ #include <stdio.h> #include <sys/socket.h> #include <ne

Linux Socket程式設計例項(一個Hello World程式)

在Linux下寫了個小的socket程式,分為客戶端和伺服器端,服務端開一個埠(2000),做為一個daemon,等待客戶的連線請求.一旦有客戶連線,伺服器端打印出客戶端的IP地址和埠,並且向伺服器端傳送歡迎資訊和時間.下面是服務端的程式碼(tcpserver.c).由於這只是個簡單的程式,所

HDFS簡單程式設計例項檔案合併

 下圖顯示了HDFS檔案系統中路徑為“localhost:50070/explorer.html#/user/hadoop”的目錄中所有的檔案資訊: 對於該目錄下的所有檔案,我們將執行以下操作: 首先,從該目錄中過濾出所有後綴名不為".abc"的檔案。 然後,對過濾之後的檔案進行讀取。

MFC介面程式設計基礎(21)一個簡單的CArchive類用法的示例(Ex_Archive)

上一篇:MFC介面程式設計基礎(20):一個簡單的文件序列化示例(Ex_SDIArchive) 下一篇:MFC介面程式設計基礎(22):MFC ODBC連線資料庫 第一步 用MFC 應用程式嚮導建立一個預設

MFC介面程式設計基礎(20)一個簡單的文件序列化示例(Ex_SDIArchive)

上一篇:MFC介面程式設計基礎(19):文件檢視結構應用程式例子(Editor) 下一篇:MFC介面程式設計基礎(21):一個簡單的CArchive類用法的示例(Ex_Archive) 第一步 用MFC應用

Linux網路程式設計(2)簡單的TCP回射伺服器Echo Server)

先介紹一下TCP伺服器大概的工作流程。首先,和TCP客戶端一樣,需要建立一個套接字,然後必須給套接字繫結一個埠。這一點和TCP客戶端不同。如果TCP客戶端不明確繫結埠的話,核心會自動為socket繫結一個可用的埠。當然,TCP客戶端也可以主動繫結一個埠。繫結埠以後,開始監聽

自定義控制元件四一個簡單的自定義控制元件例項

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/24252901 很多的Android入門程式猿來說對於Android自定義View,可能都是比較恐懼的,但是這又是高手進階的必經之路,所有準備在

spring一個簡單例項之對DAO的支援

spring 對 DAO 的支援~~ 1、在 MySQL 中建立 db_spring 資料庫,新建 t_student 表 DROP TABLE IF EXISTS `t_student`; C

.Net Core 跨平臺一個簡單程式的多平臺(windows、Linux、osx)釋出

.Net Core 跨平臺:一個簡單程式的多平臺(windows、Linux、osx)釋出     .Net Core 3.0 已於2019年9月23日釋出了,包含了一些新特性,具體參見Announcing .NET Core 3.0 .NET Core是一個跨平臺,高效能,開放原

初遇C#一個簡單的小程序(圓形周長,面積計算器)

編碼 雙精度 崩潰 輸入 面向對象 窗口 語句 readline 面向對象的語言 作為一個面向對象的語言,與用戶的交互很關鍵! 在此,我們可以先分析一下我們這個小程序要與用戶交互的內容:1.命名很重要,讓用戶看見這個程序就知道這個程序的作用。 2.當用戶打開這個程序時,提示

學習 WebService 第三步一個簡單的實例(SoapUI測試REST項目)

方法 資源 ima .com required tle margin 導出 ont 原文地址:SOAPUI測試REST項目(六)——REST服務和WADL ↑↑↑ 原文用的SoapUI,2018-3-19時,這個軟件已經更名為ReadyAPI(集成了SoapUI),因此下文

初學html,任務1一個簡單html頁面,要求內容頁面裝一篇文章 用html來分段

enter pos 工程師 分享圖片 visit 技術 運行 並且 center 這是主要內容部分,用html實現版塊分布。 接下來是樣式部分。 讓頁面所有元素的padding和margin都設置為0 ; 否則加入一張大的覆蓋的背景圖片後,會由於瀏覽器的緣故,圖片周邊有

flask學習一個簡單案例綜合之前學到的知識

黑馬的免費視訊課關於入門flask的我看完了,最後第五章實現了一個小案例,基本涵蓋了之前學到的所有知識。跟著敲了一遍,覺得還不錯,因此把程式碼在這裡分享一下。重要地方也都做了記錄。 前端截圖如下: (竟然支援qq截圖直接複製,csdn真的是越來越優秀了,點贊!!!) from

How Tomcat Works 2一個簡單的Servlet 容器

這一章的主要內容是講解如何構造自己的Servlet 容器。 我們首先看一個servlet 容器需要做什麼工作來為一個servlet 來提供HTTP請求。 Servlet 程式設計是通過 javax.servlet 和 javax.servlet.http 這兩個包的類和介面來實現的。這裡面最