# TCP connection
#### 這是可以參考的資料
https://dangerlover9403.pixnet.net/blog/post/212391408-%5B%E6%95%99%E5%AD%B8%5Dc++-socket%E8%B3%87%E6%96%99%E6%95%B4%E7%90%86
## 很搞剛的設定
如果你是用Visual C++ 來做這次的實作的話,建議你先做以下設定。
<b>專案</b> ==> <b>屬性</b> ==> <b>c/c++</b> ==> <b>前置處理器</b> ==> <b>點開前置處理器定義</b> ==> <b>編輯</b>
我們要來定義一寫東西

加入
``
_CRT_SECURE_NO_WARNINGS
``
如此一來才可以在VC內用strcpy等<string.h>內定義的許多工具,否則他會一直跑warning教你改成strcpy_s
\
\
``
_WINSOCK_DEPRECATED_NO_WARNINGS
``
如此一來才可以在VC內用inet_ntoa這個工具,否則他會一直跑教你調一些有的沒的
<b>這些設定簡單來說就是叫VC to Shut up,我想這樣寫你...你別管我!</b>
\
\
## 簡單介紹
首先我們先來定義一下傳輸的概念,當傳輸端(不管是server、client),都要必需先傳輸資料,並且進入一個while loop等待接收端的ACK回應,直到有接收到程式才可以繼續往下跑
```c=21
void send_and_wait(){
send(clientSocket, temp, strlen(temp), 0);
int bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
}
```
\
<b>我們可以看下面的應用</b>
```c=94
// Here is for the first menu
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "--- Menu ---");
send_and_wait();
strcpy(temp, "1. Read all existing message.");
send_and_wait();
strcpy(temp, "2. Write a new message");
send_and_wait();
strcpy(temp, "Please type \"1\"" " or \"2\" " "to select an option");
send_and_wait();
// // Finish line
strcpy(temp, "#");
send_and_wait();
```
以上是server端傳給 client 的 Menu,先將要傳輸的資料填入全域變數temp內,在套用send_and_wait()來進行傳輸。
\
\
<b>client端這邊也有特別的東西</b>
```c=14
void receive_function() {
int bytesRead = 0;
while (1) {
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
}
send(serverSocket, buf, bytesRead, 0);
if (buf[0] == '#') {
break;
}
buf[bytesRead] = '\0';
printf("%s", buf);
printf("\n");
}
}
```
\
這是client用來持續接收訊息的function,若收到server端傳來的終止訊號"#",就會斷開來。
# 程式簡介
## server端
include 函式庫
```c=2
#pragma comment(lib, "wsock32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 2048
#define MY_ERROR(s) printf(s); system("PAUSE"); exit(1);
char store[5000];
char temp[100];
int ptr = 0;
char buf[MAX_SIZE + 1];
SOCKET serverSocket, clientSocket; // create a socket
```
\\
特別的function
```c=14
void end() {
for (int i = 0; i < 5; i++) {
store[ptr] = '%';
ptr = ptr + 1;
}
}
void send_and_wait(){
send(clientSocket, temp, strlen(temp), 0);
int bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
}
```
send_and_wait()上面有提到
end()的用意是來做儲存料的尖閣區分,每筆資料用5個%來分隔
例如: 用戶輸入hello,再輸入yo9968,我會在store陣列內儲存hello%%%%%yo9968%%%%%,以用來做判斷上的區分。
\
\
\
fixed variable set port
預設port 為 83
```c=35
int serverPort = 83;
// here is for define IP port
// If the file get input
if (argc == 2) {
serverPort = atoi(argv[1]);
}
```
這個前面的設定自己看,裡面有註解
```c=44
// call WSAStartup first for Winsock
WSADATA wsadata;
// MAKEWORD(2,2) mean version 2.2
// the second parameter means open a wsadata
if (WSAStartup(MAKEWORD(2, 2), (LPWSADATA)&wsadata) != 0) {
printf("123");
MY_ERROR("Winsock Error\n");
}
// Create socket
// PF_INET is for ipv4
// SOCK_STREAM is for TCP
serverSocket = socket(PF_INET, SOCK_STREAM, 0);
// Set the server information
// initialization address array
memset(&serverAddress, 0, sizeof(serverAddress));
// just for IPV4
serverAddress.sin_family = AF_INET;
// set the server IP to any
serverAddress.sin_addr.s_addr = INADDR_ANY;
// set the server Ip to the host
//serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(serverPort); //converts a u_short from host to TCP/IP network byte order
// Bind the socket
if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
MY_ERROR("Bind Error\n");
}
// Prepare to listen to the incoming clients
// the second parmeter is for the max listening for client
if (listen(serverSocket, 3) < 0) {
MY_ERROR("Listen Error\n");
}
```
\
\
<b>進入while loop後.......</b>
\
\
server 端要持續偵測是否有client要進來
```c=87
// Accept a client
clientAddressLen = sizeof(clientAddress);
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressLen);
if (clientSocket == INVALID_SOCKET){
continue;
}
```
\
\
接下來要持續偵測,直到client有船東西過來,最後送ACK回去給client做確認
```c=110
// Receive the data from the client, and send it back
// it will return the data length
bytesRead = 0;
while(bytesRead == 0){
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
buf[bytesRead] = '\0';
send(clientSocket, buf, bytesRead, 0);
```
\
\
輸出傳輸狀況,以確認連線的正確性
```c=119
//inet_ntoa function is for turn binary IP to decimal Ip address
//printf("Client IP is : %s \n", inet_ntoa(clientAddress.sin_addr));
printf("Receive %d byte(s): %s\n", bytesRead, buf);
printf("Client IP is : %s \n", inet_ntoa(clientAddress.sin_addr));
```
\
\
<b>如果是Menu 的狀況二的話</b>
\
\
先傳給client前導訊息
```c=123
if (buf[0] == '2' && strlen(buf) == 1) {
// This is for initial
strcpy(temp, "------------------------------");
send_and_wait();
strcpy(temp, "start to write something");
send_and_wait();
strcpy(temp, "#");
send_and_wait();
```
\
\
等待client傳入要寫入的資料
```c=132
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
printf("Receive %d byte(s): %s\n", bytesRead, buf);
buf[bytesRead] = '\0';
for (int i = 0; i < bytesRead-1; i++) {
store[ptr] = buf[i];
ptr = ptr + 1;
}
end();
```
最後傳輸終止訊號,告訴client停止持續接受訊息
```c=144
strcpy(temp,"#");
send(clientSocket, temp, strlen(temp), 0);
continue;
}
```
\
\
<b>如果是Menu 的狀況一的話</b>
\
\
跟前面的概念差不多,就只是在做字串的解析而已
```c=149
else if (buf[0] == '1' && strlen(buf) == 1) {
// send the line first
strcpy(temp, "------------------------------");
send_and_wait();
strcpy(temp, "All messages:");
send_and_wait();
// connection can't break
for (int i = 0; i < ptr; i++) {
if (store[i] != '%') {
temp[piv] = store[i];
piv = piv + 1;
continue;
}
else {
for (int k = 1; k <= 4; k++) {
if (store[i + k] != '%') {
no = 1;
break;
}
}
}
if (no == 1) {
temp[piv] = store[i];
piv = piv + 1;
no = 0;
continue;
}
send(clientSocket, temp, piv, 0);
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
piv = 0;
buf[bytesRead] = '\0';
i = i + 4;
}
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "\n");
send_and_wait();
send(clientSocket, "#", 1, 0);
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
```
最後記得要把socket關掉
```c=213
closesocket(clientSocket);
```
\
\
## Client端
我覺得概念差不多,我就不詳述了科科
# 完整code
## server.c
```c=
#pragma comment(lib, "wsock32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 2048
#define MY_ERROR(s) printf(s); system("PAUSE"); exit(1);
char store[5000];
char temp[100];
int ptr = 0;
char buf[MAX_SIZE + 1];
SOCKET serverSocket, clientSocket; // create a socket
void end() {
for (int i = 0; i < 5; i++) {
store[ptr] = '%';
ptr = ptr + 1;
}
}
void send_and_wait(){
send(clientSocket, temp, strlen(temp), 0);
int bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
}
int main(int argc, char* argv[]) {
struct sockaddr_in serverAddress, clientAddress; // sockaddr_in
int clientAddressLen;
int bytesRead;
int no = 0;
int serverPort = 83;
// here is for define IP port
// If the file get input
if (argc == 2) {
serverPort = atoi(argv[1]);
}
// call WSAStartup first for Winsock
WSADATA wsadata;
// MAKEWORD(2,2) mean version 2.2
// the second parameter means open a wsadata
if (WSAStartup(MAKEWORD(2, 2), (LPWSADATA)&wsadata) != 0) {
printf("123");
MY_ERROR("Winsock Error\n");
}
// Create socket
// PF_INET is for ipv4
// SOCK_STREAM is for TCP
serverSocket = socket(PF_INET, SOCK_STREAM, 0);
// Set the server information
// initialization address array
memset(&serverAddress, 0, sizeof(serverAddress));
// just for IPV4
serverAddress.sin_family = AF_INET;
// set the server IP to any
serverAddress.sin_addr.s_addr = INADDR_ANY;
// set the server Ip to the host
//serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(serverPort); //converts a u_short from host to TCP/IP network byte order
// Bind the socket
if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
MY_ERROR("Bind Error\n");
}
// Prepare to listen to the incoming clients
// the second parmeter is for the max listening for client
if (listen(serverSocket, 3) < 0) {
MY_ERROR("Listen Error\n");
}
int piv = 0;
while (1) {
// Accept a client
clientAddressLen = sizeof(clientAddress);
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressLen);
if (clientSocket == INVALID_SOCKET){
continue;
}
// Here is for the first menu
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "--- Menu ---");
send_and_wait();
strcpy(temp, "1. Read all existing message.");
send_and_wait();
strcpy(temp, "2. Write a new message");
send_and_wait();
strcpy(temp, "Please type \"1\"" " or \"2\" " "to select an option");
send_and_wait();
// // Finish line
strcpy(temp, "#");
send_and_wait();
// Receive the data from the client, and send it back
// it will return the data length
bytesRead = 0;
while(bytesRead == 0){
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
buf[bytesRead] = '\0';
send(clientSocket, buf, bytesRead, 0);
//inet_ntoa function is for turn binary IP to decimal Ip address
//printf("Client IP is : %s \n", inet_ntoa(clientAddress.sin_addr));
printf("Receive %d byte(s): %s\n", bytesRead, buf);
printf("Client IP is : %s \n", inet_ntoa(clientAddress.sin_addr));
if (buf[0] == '2' && strlen(buf) == 1) {
// This is for initial
strcpy(temp, "------------------------------");
send_and_wait();
strcpy(temp, "start to write something");
send_and_wait();
strcpy(temp, "#");
send_and_wait();
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
printf("Receive %d byte(s): %s\n", bytesRead, buf);
buf[bytesRead] = '\0';
for (int i = 0; i < bytesRead-1; i++) {
store[ptr] = buf[i];
ptr = ptr + 1;
}
end();
strcpy(temp,"#");
send(clientSocket, temp, strlen(temp), 0);
continue;
}
else if (buf[0] == '1' && strlen(buf) == 1) {
// send the line first
strcpy(temp, "------------------------------");
send_and_wait();
strcpy(temp, "All messages:");
send_and_wait();
// connection can't break
for (int i = 0; i < ptr; i++) {
if (store[i] != '%') {
temp[piv] = store[i];
piv = piv + 1;
continue;
}
else {
for (int k = 1; k <= 4; k++) {
if (store[i + k] != '%') {
no = 1;
break;
}
}
}
if (no == 1) {
temp[piv] = store[i];
piv = piv + 1;
no = 0;
continue;
}
send(clientSocket, temp, piv, 0);
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
piv = 0;
buf[bytesRead] = '\0';
i = i + 4;
}
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "\n");
send_and_wait();
send(clientSocket, "#", 1, 0);
bytesRead = recv(clientSocket, buf, MAX_SIZE, 0);
}
else{
// error message
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "===================================================");
send_and_wait();
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "This option is not in the menu, please enter again: ");
send_and_wait();
strcpy(temp, "\n");
send_and_wait();
strcpy(temp, "===================================================");
send_and_wait();
strcpy(temp, "#");
send_and_wait();
}
closesocket(clientSocket);
}
return 0;
}
```
## Client.c
```c=
#pragma comment(lib,"Ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define MAX_SIZE 2048
#define ADDRESS_SIZE 20
#define MY_ERROR(s) printf(s); system("PAUSE"); exit(1);
SOCKET serverSocket, clientSocket;
char buf[MAX_SIZE + 1];
void receive_function() {
int bytesRead = 0;
while (1) {
bytesRead = 0;
while (bytesRead == 0) {
bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
}
send(serverSocket, buf, bytesRead, 0);
if (buf[0] == '#') {
break;
}
buf[bytesRead] = '\0';
printf("%s", buf);
printf("\n");
}
}
int main(int argc, char* argv[]) {
int serverAddresslen;
struct sockaddr_in serverAddress;
int bytesRead;
char serverAddressStr[ADDRESS_SIZE] ;
strcpy(serverAddressStr,"127.0.0.1");
int serverPort = 83;
if (argc == 3) {
strcpy(serverAddressStr, argv[1]);
serverPort = atoi(argv[2]);
}
// call WSAStartup first for Winsock
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), (LPWSADATA)&wsadata) != 0) {
MY_ERROR("Winsock Error\n");
}
// Set the server information
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
//serverAddress.sin_addr.s_addr = inet_pton(AF_INET, serverAddressStr); // transform to 32-bit unsigned integer
inet_pton(AF_INET, serverAddressStr, &serverAddress.sin_addr);
serverAddress.sin_port = htons(serverPort); //converts a u_short from host to TCP/IP network byte order
int gate = 0;
while (1) {
// Create socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (connect(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
MY_ERROR("Connect Error\n");
}
receive_function();
scanf("%s", buf);
buf[strlen(buf)] = '\0';
//printf("Server IP is : %s \n", inet_ntoa(serverAddress.sin_addr));
// Send the data to the server, and receive it back
send(serverSocket, buf, strlen(buf)+1, 0);
bytesRead = 0;
while(bytesRead == 0){
bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
}
buf[bytesRead] = '\0';
if (buf[0] == '1' && strlen(buf) == 1) {
receive_function();
printf("\n");
gate = 0;
}
else if (buf[0] == '2' && strlen(buf) == 1) {
// start to write something
receive_function();
scanf("%s", buf);
buf[strlen(buf)] = '\0';
send(serverSocket, buf, strlen(buf)+1, 0);
bytesRead = 0;
while(bytesRead == 0){
bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
}
printf("%s", "New Message sent");
printf("%s", "\n");
buf[bytesRead] = '\0';
gate = 0;
continue;
}
else {
// receiving error message
receive_function();
}
closesocket(serverSocket);
}
return 0;
}
```