1. 程式人生 > >C語言 Socket入門示例1—— 單工通訊(客戶端向伺服器傳送訊息)

C語言 Socket入門示例1—— 單工通訊(客戶端向伺服器傳送訊息)

        如果對Windows API不太熟悉、對TCP/IP通訊協議不太熟悉,或者對C語言本身不太熟悉的話,學習Socket會有點難受的。以前學習作業系統的時候,被API嚇怕了,很多莫名其妙的API有著多如牛毛的引數,令人費解。學習計算機網路的時候,又有那麼多的協議,並且很多協議本身比較複雜,什麼三次握手建立連線,什麼四次握手釋放連結等等,也沒有學得特別透徹。更遺憾的是,以前學C的時候,誤以為自己把C學會了,誤以為C就那麼幾個標頭檔案而已,就一個黑框子而已。

        現在,經過一段時間的痛苦磨練,又有了一些新的認識:API並沒有想象的那麼難,只要把每個引數及返回值的含義以及各種資料型別之間的關係和轉換方法弄明白了,API就可以靈活運用了。TCP/IP協議,其實對所有的通訊協議都一樣,不要忽略RFC文件,只要花足夠的時間把協議的原理理解透了(最好自己能夠隨手畫出來),接下來根據協議編寫程式就順理成章了。關於C/C++我過去低估了它的難度,也低估了它的功能,所以現在繼續深入學習,以獲得更多的精髓。

        下面將一個簡單的C/S架構Socket程式程式貼出來,我也Request For 大家 Comments

1、服務端(Server):

#include <stdio.h>  
#include <winsock2.h>  
#pragma comment(lib,"ws2_32.lib")	//把ws2_32.lib加到Link頁的連線庫  
#define PORT 15001					//通訊的埠(指伺服器端)
#define ERROR 0  
#define BUFFER_SIZE 1024			//注意:此Server端資料接收緩衝區 >= Client端資料傳送緩衝區 ,否則造成緩衝區溢位
/*
	服務端原理:
		1、伺服器程序建立套接字
		2、將本地地址繫結到所建立的套接字上,以三元組{<通訊協議>,<IP地址>,<埠號>}在網路上標識該套接字
		3、將套接字置入監聽模式,並準備接受連線請求
*/
int main()  
{  
	WSADATA WSAData;  
	if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //啟動winsock ,WSAStartup()函式對Winsock DLL進行初始化
	{  
		printf("Socket initialize fail!\n");  
		exit(1);  
	}  
	SOCKET sock;										//服務程序建立套接字控制代碼(用於監聽)
	if((sock=socket(AF_INET,SOCK_STREAM,0))==ERROR)		//呼叫socket()函式建立一個流套接字,引數(網路地址型別,套接字型別,網路協議)
	{ 
		printf("Socket create!\n");  
		WSACleanup();  
		exit(1);  
	}  
	struct sockaddr_in ServerAddr;			//sockaddr_in結構用來標識TCP/IP協議下的地址,可強制轉換為sockaddr結構
	ServerAddr.sin_family=AF_INET;			//sin_family欄位必須設為AF_INET,表示該Socket處於Internet域
	ServerAddr.sin_port=htons(PORT);		//sin_port欄位用於指定服務埠,注意避免衝突
	ServerAddr.sin_addr.s_addr=INADDR_ANY;  //sin_addr欄位用於把一個IP地址儲存為一個4位元組的數,無符號長整型,根據不同用法還可表示本地或遠端IP地址
	if(bind(sock,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr))==SOCKET_ERROR)  //呼叫bind()函式將本地地址繫結到所建立的套接字上,以在網路上標識該套接字
	{   
		printf("Bind fail!\n");  
		closesocket(sock);  
		WSACleanup();  
		exit(1);  
	}  
	printf("Server Socket Port:%d\n",ntohs(ServerAddr.sin_port));  
	if(listen(sock,10)==SOCKET_ERROR)		//呼叫listen()函式將套接字置入監聽模式並準備接受連線請求,引數(已捆綁未連線的套接字描述字,正在等待連線的最大佇列長度)
	{ 
		printf("Listen fail!\n");  
		closesocket(sock);  
		WSACleanup();  
		exit(1);  
	}  

	SOCKET msgsock;			//建立一個新的套接字(用於接收accept函式的返回值,即表示已經接受的那個客戶端的連線,進而接收Client發來的資料)
	char buf[BUFFER_SIZE];  //資料接收緩衝區
	while(1)  
	{  
		if((msgsock=accept(sock,(LPSOCKADDR)0,(int *)0))==INVALID_SOCKET)  //進入監聽狀態後,呼叫accept()函式接收客戶端的連線請求,並把連線傳給msgsock套接字,原sock套接字繼續監聽其他客戶機連線請求
		{  
			printf("Accept fail!\n");  
			continue;  
		}  
		memset(buf,0,sizeof(buf));											//初始化資料接收緩衝區
		recv(msgsock,buf,BUFFER_SIZE,0);									//接收客戶端傳送過來的資料  
		if(buf[0]=='e' && buf[1]=='x' && buf[2]=='i' && buf[3]=='t')		//"exit"命令,退出程式
		{  
			printf("The End.\n");  
			break;  
		}
		printf("C:\\Socket\\Server>%s",buf);  
		closesocket(msgsock);  
	}  

	closesocket(sock); //關閉套接字  
	WSACleanup();	   //終止對Winsock DLL的使用,並釋放資源
	return 0;
}   


2、客戶端(Client):

#include <winsock2.h>  
#include <stdio.h>  
#pragma comment(lib,"ws2_32.lib")	//把ws2_32.lib加到Link頁的連線庫  
//#define IP "172.18.68.243"			//在兩臺計算機上測試,IP為Server端的IP地址  
#define IP "127.0.0.1"				//在一臺計算機上測試,IP為本地回送地址
#define PORT 15001					//注意:客戶端設定通訊的埠 = 服務端的埠
#define BUFFER_SIZE 1024			//資料傳送緩衝區大小

int main()  
{  
	char buf[BUFFER_SIZE];								//buf陣列存放客戶端傳送的訊息  
	int inputLen;										//用於輸入字元自增變數
	while(1)  
	{  
		printf("C:\\Socket\\Client>");  
		inputLen=0;  
		memset(buf,0,sizeof(buf));  
		while((buf[inputLen++]=getchar())!='\n')		//輸入以回車鍵為結束標識
		{
			;
		}
		if(buf[0]=='e' && buf[1]=='x' && buf[2]=='i' && buf[3]=='t')  
		{  
			printf("The End.\n");  
			break;   
		}  

		WSADATA WSAData;  
		if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //WSAStartup()函式對Winsock DLL進行初始化
		{  
			printf("Socket initialize fail!\n");  
			continue;  
		}  
		SOCKET sock;											//客戶端程序建立套接字
		if((sock=socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR)  //建立流套接字(與服務端保持一致)
		{  
			printf("Socket create fail!\n");  
			WSACleanup();  
			continue;  
		}  

		struct sockaddr_in ClientAddr;				//sockaddr_in結構用來標識TCP/IP協議下的地址,可強制轉換為sockaddr結構
		ClientAddr.sin_family=AF_INET;				//指Internet域
		ClientAddr.sin_port=htons(PORT);			//指定服務端所預留的埠
		ClientAddr.sin_addr.s_addr=inet_addr(IP);	//指定服務端所繫結的IP地址
		if(connect(sock,(LPSOCKADDR)&ClientAddr,sizeof(ClientAddr))==SOCKET_ERROR)  //呼叫connect()函式,向伺服器程序發出連線請求  
		{ 
			printf("Connect fail!\n");  
			closesocket(sock);  
			WSACleanup();  
			continue;  
		}  
		send(sock,buf,BUFFER_SIZE,0);				 //向伺服器傳送資料 
		closesocket(sock);							 //關閉套接字
		WSACleanup();								//終止對Winsock DLL的使用,並釋放資源,以備下一次使用
	}  
	return 0;
}  

執行效果圖:

(1)客戶端傳送

(2)服務端接收


相關推薦

C語言 Socket入門示例1—— 通訊客戶伺服器傳送訊息

        如果對Windows API不太熟悉、對TCP/IP通訊協議不太熟悉,或者對C語言本身不太熟悉的話,學習Socket會有點難受的。以前學習作業系統的時候,被API嚇怕了,很多莫名其妙的API有著多如牛毛的引數,令人費解。學習計算機網路的時候,又有那麼多的協議

Go語言伺服器開發客戶伺服器傳送資料並接收返回資料

客戶端向伺服器傳送資料並接收返回資料。 示例程式碼: package mysocket import ( "fmt" "io" "net" ) func MySocketBase() { var ( host = "www.apache.org" p

如何利用C語言來獲取當地時間和UTC時間 設當地時間是北京時間

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

利用C語言生成的資料作圖-並生成SVG不借助任何作圖工具

=" 1.00E+02 3.50E+02 1.04E+02 3.21E+02 1.08E+02 2.46E+02 1.11E+02 1.54E+02 1.15E+02 8.06E+01 1.19E+02 5.38E+01 1.23E+02 8.31E+01 1.26E+02 1.56E+02 1.30E+02

C#使用socket實現FTP、POP3、SMTP的客戶 (一)

概述 socket本質是程式設計介面,是對TCP/IP的封裝。 TCP/IP是傳輸層的協議。 FTP、POP3、SMTP都是應用層的協議,是基於TCP/IP協議的。 所以,我們使用socket實現上述幾種協議的客戶端,其實是對藉助socket對TCP/I

C語言,結構體中字串的宣告採用字元指標還是字元陣列

      結構體中,字串選項是用字元陣列表示好,還是用字元指標表示好? typedef struct person{ char *name; int age; char sex[6]; }       該結構體中name用的是指標而不是陣列,所以需要給字串在堆上申

Linux下c語言實驗Websocket通訊客戶伺服器測試程式碼

Websocket是一種可雙向通訊的網路協議,其底層的資料收發是基於socket的,所以使用c語言來實現理論上是沒有問題的,主要難點在於協議中要求對個別資料進行加密處理,這些加密方法(庫)在java、c#等專門開發web的平臺中都是自帶的API(隨調隨到),而在用到c

如何利用C語言來獲取當地時間和UTC時間 設當地時間是北京時間

                #include  <stdio.h>  #include  <time.h>  int main(){ time_t t = time(NULL);  tm *tp = localtime(&t);   // 北京時間 printf("%d/%

C語言編程 字符串的旋轉左旋右旋及判斷

ret 規律 首字符 stdlib.h 過程 \n 題目 main 元素 此前不太熟悉這種類型的題目,特此做一個合計的方法總結。包括字符串中字符的左旋(右旋),和判斷一個字符串是否是由另一個字符串旋轉(左旋或者右旋)而來。 一.字符串的左旋(右旋) 由於左旋和右旋思路一致,

android socket 通訊客戶) 發送數據

exc ring private soc 頭信息 tput output vid array /** ClientSocket通訊類 **/ public class ClientSocket { /**服務器地址*/ private String serve

socket通訊客戶伺服器的簡單實現

什麼是socket? socket最開始的含義是一個地址和埠對(ip, port)。Socket又稱"套接字",應用程式通常通過"套接字"向網路發出請求或者應答網路請求。 socket地址API:它唯一的表示了使用tcp通訊的一端,也可以將其理解成socket地址。 socket

C#伺服器客戶通訊客戶

客戶端登陸介面 先定義三個視窗級變數(全域性變數) private TcpClient client;         private NetworkStream stream;         private

基於TCP的socket套接字的網路程式設計客戶/服務模式

於資料完整性要求較高的場合,就應採用TCP協議。 IP網路層提供IP定址和路由。因為在網路上資料可以經由多條線路到達目的地,網路層負責找出最佳的傳輸線路。 IP地址與資料包:   IP層就是把資料分組從一個主機跨越千山萬水搬運到另外一主機, 並且這搬運服務一點都不可靠, 丟包、

CAS點登入客戶、服務搭建

一、單點登入簡介 單點登入(Single Sign On),簡稱為 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,使用者只需要登入一次就可以訪問所有相互信任的應用系統。 CAS 是一個開源的企業級單點登入系統,CAS 包含兩個部分:CAS Serve

Java Socket程式設計 檔案傳輸客戶伺服器下載一個檔案

用於客戶端從伺服器端下載檔案 伺服器(Server) package com.socket.sample; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.i

Socket通訊客戶伺服器對話

科技改變時代…… 1/Socket 1,什麼是Socket 網路上的兩個程式通過一個雙向的通訊連線實現資料的交換,這個雙向鏈路的一端稱為一個Socket。Socket通常用來實現客戶方和服務方的連線。Socket是TCP/IP協議的一個十分流行的程

Java NIO學習筆記(四) 使用JDK 1.7 NIO2.0 實現客戶伺服器通訊

JDK1.7 提供了全新的非同步NIO模式。稱為:NIO2.0或AIO。該模式引入了新的非同步通道的概念,並提供了非同步檔案通道和非同步套接字通道的實現。非同步通道提供兩種方式獲取獲取操作結果。分別是: 通過java.util.concurrent

Android簡單實現Socket通訊客戶連線伺服器後,伺服器客戶傳送文字資料

案例實現的是簡單的Socket通訊,當客戶端(Android客戶端)連線到指定伺服器以後,伺服器向客戶端傳送一句話文字資訊(你可以拓展其它的了) 先看一下服務端程式的實現吧 Server.java import java.io.IOException;

Spring Boot+Socket實現與html頁面的長連線,客戶伺服器訊息伺服器客戶輪詢傳送訊息,附案例原始碼

功能介紹 客戶端給所有線上使用者傳送訊息 客戶端給指定線上使用者傳送訊息 伺服器給客戶端傳送訊息(輪詢方式) 注意:socket只是實現一些簡單的功能,具體的還需根據自身情況,程式碼稍微改造下 專案搭建 專案結構圖   pom.xml <?xml version="1.0" encod

C語言系列必讀技術書推薦從入門到進階+技術書閱讀方法論

轉載自某大佬部落格:https://pymlovelyq.github.io/2018/10/10/CC/ 前言:技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好