linux socke程式設計例項:一個簡單的echo伺服器程式
也許很多朋友會像我一樣,這樣的程式在Java寫得太多,以至對Socket的通訊細節還不曾忘懷。由於未有linux下的程式設計經驗,在寫程式過程中碰到很多不懂的東西,經過google一翻後,終於把一些基本的東西搞懂了。好了,閒話少講,下面說說程式設計的想法。
本文編的是echo伺服器示例程式,當收到客戶端的資料,伺服器把資料不經加工地傳送給客戶。採用TCP連線,採用埠8080進行設計,在整個過程中主要涉及socket的通訊。
首先建立一個 socket,程式碼如下:
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網路地址
- SOCK_STREAM
- 提供穩定可靠的連線,並且是雙向的通訊方式,如TCP。
- SOCK_DGRAM
- 提供無連線的資料報通訊,如UDP。
- SOCK_RAW
- 提供該問內部網路協議和網路介面, 只有root使用者才可以使用些協議。
返回值:成功則返socket描述符,出錯則返回-1,可通過errno程式碼進行檢視錯誤原因。
再次,把socket繫結到本機上,程式碼如下:
struct sockaddr_in sa;
bzero(&sa, sizeof(sa));
sa.sin_family
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 這兩個包的類和介面來實現的。這裡面最