1. 程式人生 > >流式套接字C/S通訊程式

流式套接字C/S通訊程式

客戶端

#include"stdafx.h"
#define WIN32_LEAN_AND_MEAN
#include<Windows.h>
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdlib.h>
#include<stdio.h>

//連線到winsock2對應的lib檔案:ws2_32.lib,Mswsock.lib,Advapi32.lib
#pragma comment (lib,"Ws2_32.lib")
#pragma comment (lib,"Mswsock.lib")
#pragma comment (lib,"AdvApi32.lib")

//定義預設的緩衝區長度和埠號
#define DEFAULT_BUFLEN 512  
#define DEFAULT_PORT "27015" 


int _cdecl main(int argc, char** argv)
{

	WSADATA wsadata;
	SOCKET Connectsocket = INVALID_SOCKET;
	struct addrinfo * result = NULL,*ptr = NULL,hints;
	char *sendbuf = "bryant_xw";
	char recvbuf[DEFAULT_BUFLEN]; 
	
	int iResult;
	int recvbuflen = DEFAULT_BUFLEN;

	//驗證引數的合法性
	if(argc != 2)
	{
		printf("usage:%s server-name\n",argv[0]);
		return 1;
	}

	//初始化套接字
	iResult = WSAStartup(MAKEWORD(2,2),&wsadata);
	if(iResult != 0)
	{
		printf("WSAStartup failed with error %d\n",iResult);
		return 1;
	}
	ZeroMemory(&hints,sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	//解析伺服器的地址和埠
	iResult = getaddrinfo(argv[1],DEFAULT_PORT,&hints,&result); //成功返回的是0
	if(iResult != 0)
	{
		printf("GetAddrInfo is failed with error %d\n",iResult);
		WSACleanup();
		return 1;
	}

	//嘗試連線伺服器地址,直到成功
	for(ptr = result; ptr!=NULL;ptr = ptr->ai_next)
	{
		//建立套接字
		Connectsocket = socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol);
		if(Connectsocket == INVALID_SOCKET)
		{
			printf("socket failed with error %ld\n",WSAGetLastError());
			WSACleanup();
			return 1;
		}
		//向伺服器發起連線
		iResult = connect(Connectsocket,ptr->ai_addr,(int)ptr->ai_addrlen);
		if(iResult == SOCKET_ERROR)
		{
			closesocket(Connectsocket);
			Connectsocket = INVALID_SOCKET;
			continue;
		}
		break;
	}
	freeaddrinfo(result);

	if(Connectsocket == INVALID_SOCKET)
	{
		printf("unable to connect to server");
		WSACleanup();
		return 1;
	}
	//傳送緩衝區的測試資料
	iResult = send(Connectsocket,sendbuf,(int)strlen(sendbuf),0);
	if(iResult ==  SOCKET_ERROR)
	{
		printf("send failed with error %ld\n",WSAGetLastError());
		closesocket(Connectsocket);
		WSACleanup();
		return 1;
	}
	printf("Bytes sent :%ld\n",iResult);

	//資料傳送結束,呼叫shutdown函式宣告不再發送資料,但是此時客戶端人可以接收資料
	iResult = shutdown(Connectsocket,SD_SEND);
	if(iResult ==  SOCKET_ERROR)
	{
		printf("shutdown failed with error %ld\n",WSAGetLastError());
		closesocket(Connectsocket);
		WSACleanup();
		return 1;
	}

	//持續接收資料,直到伺服器關閉連線
	do
	{
		iResult = recv(Connectsocket,recvbuf,recvbuflen,0);
		if(iResult > 0)
			printf("Bytes recevied: %d\n",iResult);
		else if(iResult == 0)
			printf("Connection closed\n");
		else
			printf("recv failed with error: %d\n",WSAGetLastError());
	} while (iResult > 0);
	
	//關閉套接字
	closesocket(Connectsocket);
	//釋放資源
	WSACleanup();
	return 0;
}

伺服器端

#include"stdafx.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include<Windows.h>
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdlib.h>
#include<stdio.h>

#pragma comment(lib,"Ws2_32.lib")//連線到Winsock 2 對應的lib檔案:ws2_32.lib

//定義預設的緩衝區長度和埠號
#define DEFAULT_BUFLEN 512  
#define DEFAULT_PORT "27015" 


int _cdecl main(void)
{
	WSADATA wsadata;
	int iResult;
	SOCKET ListenSocket = INVALID_SOCKET;
	SOCKET ClientSocket = INVALID_SOCKET;
	struct addrinfo *result = NULL;
	struct addrinfo hints;

	int iSentResult;
	char recvbuf[DEFAULT_BUFLEN];
	int recvbuflen = DEFAULT_BUFLEN;
	
	//初始化winsock
	iResult = WSAStartup(MAKEWORD(2,2),&wsadata);
	if(iResult != 0)
	{
		printf("WSAStartup failed with error:%d\n",iResult);
		return 1;
	}

	ZeroMemory(&hints,sizeof(hints));

	//宣告IPv4地址族,流式套接字,TCP協議
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;
	
	//解析伺服器地址和埠號
	iResult = getaddrinfo(NULL,DEFAULT_PORT,&hints,&result); //成功返回的是0
	if(iResult != 0)
	{
		printf("getaddrinfo is failed with error %d\n",iResult);
		return 1;
	}

	//呼叫socket函式建立一個流式套接字
	ListenSocket = socket(result->ai_family,result->ai_socktype,result->ai_protocol);
	if(ListenSocket == INVALID_SOCKET)
	{
		printf("socket failed with error %ld\n",WSAGetLastError());
		free(result);
		WSACleanup();
		return 1;
	}

	//為套接字繫結地址和埠號
	iResult = bind(ListenSocket,result->ai_addr,(int)result->ai_addrlen); //成功返回0
	if(iResult != 0)
	{
		printf("bind failed with error %d\n",WSAGetLastError());
		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}
	freeaddrinfo(result);

	//監聽連線請求

	iResult  = listen(ListenSocket,SOMAXCONN);//成功返回0

	if(iResult != 0)
	{
		printf("listen failed with error %d\n",WSAGetLastError()); //
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	//接收客戶端的連線請求,返回  新的  連線套接字 ClientSocket ,之後在ClientSocket上讀寫
	ClientSocket = accept(ListenSocket,NULL,NULL);  
	if(ClientSocket == INVALID_SOCKET)
	{
		printf("accept failed with error %d\n",WSAGetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}	

	
	//持續接收資料直到對方關連結
	do
	{
		iResult = recv(ClientSocket,recvbuf,recvbuflen,0);
		//case 1:成功接收資料
		if(iResult > 0)
		{
			printf("Bytes received:%d\n",iResult);
			
			//將緩衝區的內容回送給客戶端
			iSentResult = send(ClientSocket,recvbuf,iResult,0);
			if(iSentResult == SOCKET_ERROR)
			{
				printf("send failed with error %d\n",WSAGetLastError());
				closesocket(ClientSocket);
				WSACleanup();
				return 1;
			}
			printf("Bytes sent: %d\n",iSentResult);
		}

		//case 2: 連線關閉
		else if(iResult == 0)
		{
			printf("Connection closing..\n");
		}
		//case3: 接收發生錯誤
		else 
		{
			printf("recv failed with error %d\n",WSAGetLastError());
			closesocket(ClientSocket);
			WSACleanup();
			return 1;
		}

	} while (iResult > 0);

	//關閉連線
	iResult = shutdown(ClientSocket,SD_SEND);
	if(iResult != 0)
	{
		printf("shutdown failed with error %d\n",WSAGetLastError());
		closesocket(ClientSocket);
		WSACleanup();
		return 1;
	}
	//關閉套接字,釋放資源
	closesocket(ClientSocket);
	WSACleanup();
	//在必須要監聽的套接字的情況下釋放該套接字
	closesocket(ListenSocket);
	
	return 0;
}

執行的結果如下圖: 字串的初始值是bryant_xw即9個字元