1. 程式人生 > >程式設計訓練Day002——基於TCP的Socket程式設計

程式設計訓練Day002——基於TCP的Socket程式設計

這個程式算是這輩子寫的第一個完整的程式,不是今天一天寫的,之前花了四五天,不到四百行的程式碼對程式設計老鳥來說估計是分分鐘的事,但我還是挺知足的,畢竟第一次。

真正自己嘗試寫一個程式之後才發現,之前看的所有的東西都是紙上談兵,只有自己動手寫一個程式,才會理解什麼叫程式設計,從程式設計到程式編寫到程式除錯到功能優化,很多東西都是書本上學不到的。

這個程式主要實現的功能簡單的說就是TCP通訊,在通訊之上實現雙機協同工作,執行環境是windows。

貼程式碼:

#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ws2_32.lib")
#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#define PORT 8888  /*定義埠*/
#define MAXDATA 1000  /*定義最大傳輸數量*/
#define T 100

int exe(void)
{
	long i = 100000000L;
	while (i--);
	printf("	This is a program that needs to be executed !\n");
	return 0;
}

int main(void)
{
	/*各種宣告定義*/
	SOCKET server;
	SOCKET client;
	struct sockaddr_in serveraddr;
	struct sockaddr_in clientaddr;
	WSADATA wsaData;

	int len = sizeof(struct sockaddr_in);
	int runTime, serverTime_i, clientTime_i, ret_1, ret_cyc, ret_time_server, ret_time_client;
	int dec_1, sign_1, dec_2, sign_2;
	int t = T;
	int con = -1;
	char port;
	char receiveData[MAXDATA];
	char runData[MAXDATA];
	char *readyMessage_server = "I'm ready !\n";
	char *readyMessage_client = "I'm ready too !\n";
	char *runMessage = "Run !\n";
	char serverTime_c[MAXDATA], *serverTime_c_server, clientTime_c[MAXDATA], *clientTime_c_client;
	char waitTime, serverTime_d, clientTime_d;
	clock_t start, end;

	/*選擇伺服器或客戶端*/
	printf("Please choose server of client.\nA.Server	B.Client\n");
	scanf("%c", &port);

	/*伺服器*/
	if (port == 'A' || port == 'a')
	{
		/*啟動windows的socket服務,初始化WSA*/
		WSAStartup(0x101, &wsaData);

		/*建立服務端,初始化伺服器地址*/
		memset((void *)&serveraddr, 0, sizeof(serveraddr));

		/*建立伺服器套接字*/
		server = socket(AF_INET, SOCK_STREAM, 0);
		if (server == -1)
		{
			printf("Socket error !");
		}

		/*繫結IP和埠*/
		serveraddr.sin_family = AF_INET;  /*定義家族協議*/
		serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");  /*定義主機地址*/
		serveraddr.sin_port = htons(PORT);  /*定義主機埠*/
		if (bind(server, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)  /*繫結成功返回0*/
		{
			printf("Bind error !");
			getchar();
			exit(1);
		}

		/*開始監聽*/
		if (listen(server, 20) == -1)
		{
			printf("Listen error !");
			getchar();
			exit(1);
		}

		/*建立連線*/
		printf("Waiting for connection...\n\n");
		client = accept(server, (SOCKADDR *)&clientaddr, &len);
		if (client == -1)
		{
			printf("accept error !");
			getchar();
			exit(1);
		}
		printf("Receive a connection: %s \r\n\n", inet_ntoa(clientaddr.sin_addr));

		/*傳送準備資訊*/
		if (send(client, readyMessage_server, strlen(readyMessage_server), 0) < 0)
		{
			printf("\n\nSend error or connection interruption !\n");
			getchar();
			exit(1);
		}

		/*接受準備資訊*/
		int ret_1 = recv(client, receiveData, MAXDATA, 0);
		if (ret_1 > 0)
		{
			receiveData[ret_1] = 0x00;
			printf("From client %s: %s", inet_ntoa(clientaddr.sin_addr), receiveData);
		}
		/*接收不到客戶端資料時中斷迴圈*/
		else
		{
			printf("\n\nReceive error or connection interruption !\n");
			getchar();
			exit(1);
		}

		/*發出執行許可指令*/
		if (strcmp(receiveData, readyMessage_client) == 0)
		{
			;
			if (send(client, runMessage, strlen(runMessage), 0) < 0)
			{
				printf("\n\nSend error or connection interruption !\n");
				getchar();
				exit(1);
			}
		}

		while (1)
		{
			/*執行時間大於週期時間,則直接執行*/
			if (t >= T)
			{
				/*計時開始*/
				start = clock();

				exe();

				/*計時結束*/
				end = clock();

				/*服務端執行用時*/
				serverTime_d = (double)(end - start);

				/*服務端執行用時轉字串*/
				_ecvt(serverTime_d, 10, &dec_1, &sign_1);
				serverTime_c_server = _ecvt(serverTime_d, dec_1, &dec_2, &sign_2);

				printf("Operation time is %s\n\n", serverTime_c_server);

				/*傳送服務端執行用時*/
				if (send(client, serverTime_c_server, strlen(serverTime_c_server), 0) < 0)
				{
					printf("\n\nSend error or connection interruption !\n");
					getchar();
					exit(1);
				}

				/*接收客戶端執行用時*/
				ret_time_client = recv(client, clientTime_c, MAXDATA, 0);
				if (ret_time_client > 0)
				{
					clientTime_c[ret_time_client] = 0x00;
				}
				else
				{
					printf("\n\nReceive error or connection interruption !\n");
					getchar();
					exit(1);
				}

				/*字串轉整形*/
				serverTime_i = atoi(serverTime_c_server);
				printf("Server's operation time is %d\n", serverTime_i);
				clientTime_i = atoi(clientTime_c);
				printf("Client's operation time is %d\n", clientTime_i);

				/*比較服務端、客戶端用時長短*/
				if (serverTime_i >= clientTime_i)
				{
					runTime = serverTime_i;
				}
				else
				{
					runTime = clientTime_i;
				}

				t = runTime;

				printf("The whole system's opration time is %d\n\n", t);

				/*執行總時長小於週期時間,掛起*/
				if (t <= T)
				{
					waitTime = T - t;
					Sleep(waitTime);
					t = T;
				}
			}
		}

		/*客戶端關閉,提示連線中斷*/
		printf("Connection interruption !\n");
		getchar();
		exit(1);
	}

	/*客戶端*/
	else
	{
		/*啟動windows的socket服務,初始化WSA*/
		WSAStartup(0x101, &wsaData);

		/*建立服務端,初始化伺服器地址*/
		memset((void *)&clientaddr, 0, sizeof(clientaddr));

		/*建立伺服器套接字*/
		client = socket(AF_INET, SOCK_STREAM, 0);
		if (client == -1)
		{
			printf("Socket error !");
			getchar();
			exit(1);
		}

		/*繫結IP和埠*/
		clientaddr.sin_family = AF_INET;  /*定義家族協議*/
		clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  /*定義主機地址*/
		clientaddr.sin_port = htons(PORT);  /*定義主機埠*/

		while (1)
		{
			/*連線中斷,跳出迴圈,提示連線中斷*/
			if (con == 1)
			{
				break;
			}

			/*啟動程式時迴圈連線服務端*/
			while (con == -1)
			{
				con = connect(client, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
				if (con == -1)
				{
					printf("Connection error !\n");
				}
			}

			/*接收準備資訊*/
			ret_1 = recv(client, receiveData, MAXDATA, 0);
			if (ret_1 > 0)
			{
				receiveData[ret_1] = 0x00;
				printf("From server: %s", receiveData);
			}
			/*接受不到客戶端資料時中斷迴圈*/
			else
			{
				printf("\n\nReceive error or connection interruption !\n");
				getchar();
				exit(1);
			}

			/*傳送準備資訊*/
			if (send(client, readyMessage_client, strlen(readyMessage_client), 0) < 0)
			{
				printf("\n\nSend error or connection interruption !\n");
				getchar();
				exit(1);
			}

			/*接收執行許可指令*/
			ret_cyc = recv(client, runData, MAXDATA, 0);
			if (ret_cyc > 0)
			{
				runData[ret_cyc] = 0x00;
				printf(runData);
			}
			/*接收不到服務端資料時中斷迴圈*/
			else
			{
				printf("\n\nReceive error or connection interruption !\n");
				getchar();
				exit(1);
			}

			/*檢驗執行許可指令並開始執行*/
			if (strcmp(runData, runMessage) == 0)
			{
				while (con == 0)
				{
					if (t >= T)
					{
						/*計時開始*/
						start = clock();

						exe();

						/*計時結束*/
						end = clock();

						/*客戶端執行用時*/
						clientTime_d = (double)(end - start);

						/*服務端執行用時轉字串*/
						_ecvt(clientTime_d, 10, &dec_1, &sign_1);
						clientTime_c_client = _ecvt(clientTime_d, dec_1, &dec_2, &sign_2);

						printf("Operation time is %s\n\n", clientTime_c_client);

						/*傳送服務端執行用時*/
						if (send(client, clientTime_c_client, strlen(clientTime_c_client), 0) < 0)
						{
							printf("\n\nSend error or connection interruption !\n");
							getchar();
							exit(1);
						}

						/*接收客戶端執行用時*/
						ret_time_server = recv(client, serverTime_c, MAXDATA, 0);
						if (ret_time_server > 0)
						{
							serverTime_c[ret_time_server] = 0x00;
						}
						else
						{
							printf("\n\nReceive error or connection interruption !\n");
							getchar();
							exit(1);
						}

						/*字串轉整形*/
						serverTime_i = atoi(serverTime_c);
						printf("Server's operation time is %d\n", serverTime_i);
						clientTime_i = atoi(clientTime_c_client);
						printf("Client's operation time is %d\n", clientTime_i);

						/*比較服務端、客戶端用時長短*/
						if (serverTime_i >= clientTime_i)
						{
							runTime = serverTime_i;
						}
						else
						{
							runTime = clientTime_i;
						}

						t = runTime;

						printf("The whole system's opration time is %d\n\n", t);

						/*執行總時長小於週期時間,掛起*/
						if (t <= T)
						{
							waitTime = T - t;
							Sleep(waitTime);
							t = T;
						}
					}
				}
			}
		}
		
		/*客戶端關閉,提示連線中斷*/
		printf("Connection interruption !\n");
		getchar();
		exit(1);
	}

	return 0;
}

因為是寫了很多天的一個程式了,功能基本能想到的都優化過了,學到的東西真的很多,大概列一列吧:

  1. Socket程式設計的思路,其中各個函式的含義
  2. 資料傳輸的阻塞和非阻塞
  3. 資料儲存的大小端(位元組序)
  4. char *a和char a[]的區別
  5. VS到底該怎麼用
  6. 其實還有很多,這些只是我暫時能想到的

其實今天是偷懶了,本來想把昨天的計算器程式完善一下的,但因為工作需要,就先這個程式收了個尾,不過加的程式碼應該超過百行了,明天繼續,希望自己可以堅持。