在HTTP 客戶端向服務器發送報文以前,須要用網際協議(Internet Protocol,IP)
地址和端口號在客戶端和服務器之間創建一條TCP/IP 鏈接。 編程
1、實驗目的 ubuntu
學習和掌握Linux下的TCP服務器基本原理和基本編程方法 服務器
2、實驗平臺 網絡
Linux操做系統 socket
3、實驗內容 tcp
編寫Linux下TCP服務器套接字程序,程序運行時服務器等待客戶的鏈接,一旦鏈接成功,則顯示客戶的IP地址、端口號,並向客戶端發送字符串。 函數
4、實驗原理 學習
使用套接字編程能夠實現基於TCP/IP協議的面向鏈接的通訊,它分爲服務器端和客戶端兩部分 spa
上爲UDP,下爲TCP 操作系統
一、socket函數:爲了執行網絡輸入輸出,一個進程必須作的第一件事就是調用socket函數得到一個文件描述符
二、connect函數:當用socket簡歷了套接口後,能夠調用connect爲這個套接字指明遠程端的地址;若是是字節流套接口,connect就使用三次握手創建一個鏈接;若是是數據報套接口,connect僅指明遠程端地址,而不向它發送任何數據。
3、bind函數:爲套接口分配一個本地IP和協議端口,對於網際協議,協議地址是32位IPv4地址或128位IPv6地址與16位的TCP或UDP端口號的組合;如指定端口爲0,調用bind時內核將選擇一個臨時端口,若是指定一個通配IP地址,則要等到創建鏈接後內核才選擇一個本地IP地址。
4、listen函數:listen函數僅被TCP服務器調用,它的做用是將用sock建立的主動套接口轉換成被動套接口,並等待來自客戶端的鏈接請求。
5、accept函數:accept函數由TCP服務器調用,從已完成鏈接隊列頭返回一個已完成鏈接,若是完成鏈接隊列爲空,則進程進入睡眠狀態。
六、write和read函數:當服務器和客戶端的鏈接創建起來後,就能夠進行數據傳輸了,服務器和客戶端用各自的套接字描述符進行讀/寫操做。由於套接字描述符也是一種文件描述符,因此能夠用文件讀/寫函數write()和read()進行接收和發送操做。
(1)write()函數用於數據的發送。
(2)read()函數用於數據的接收。
七、send和recv函數:TCP套接字提供了send()和recv()函數,用來發送和接收操做。這兩個函數與write()和read()函數很類似,只是多了一個附加的參數。
(1)send()函數用於數據的發送。
(2)recv()函數用於數據的發送。
5、實驗步驟
一、登錄進入ubuntu操做系統,新建一個文件,命名爲tcpserver.c(爲了方便起見,能夠進入「home」,再進入用戶目錄,在用戶目錄下新建tcpserver.c)。
二、在tcpserver.c中編寫服務器端程序代碼並保存。
三、在「終端」(「Applications」→「附件」→「終端」)中執行命令進入tcpserver.c所在目錄。(pwd命令能夠顯示當前所在目錄;ls命令能夠顯示當前目錄下的文件和文件夾信息;cd..命令能夠進入上一級目錄;cd 目錄名 命令能夠進入當前所示的某個目錄。)
四、執行命令gcc –o tcpserver tcpserver.c生成可執行文件tcpserver。
五、執行命令./ tcpserver,觀察結果。
六、認真分析源代碼,體會如何編寫一個TCP服務器端程序。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 1234 #define BACKLOG 1 int main() { int listenfd, connectfd; struct sockaddr_in server; struct sockaddr_in client; socklen_t addrlen; if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Creating socket failed."); exit(1); } int opt =SO_REUSEADDR; setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&server,sizeof(server)); server.sin_family=AF_INET; server.sin_port=htons(PORT); server.sin_addr.s_addr= htonl (INADDR_ANY); if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("Binderror."); exit(1); } if(listen(listenfd,BACKLOG)== -1){ /* calls listen() */ perror("listen()error\n"); exit(1); } addrlen =sizeof(client); if((connectfd = accept(listenfd,(struct sockaddr*)&client,&addrlen))==-1) { perror("accept()error\n"); exit(1); } printf("Yougot a connection from cient's ip is %s, prot is %d\n",inet_ntoa(client.sin_addr),htons(client.sin_port)); send(connectfd,"Welcometo my server.\n",22,0); close(connectfd); close(listenfd); return 0; }
5、實驗步驟
一、登錄進入ubuntu操做系統,新建一個文件,命名爲tcpclient.c(爲了方便起見,能夠進入「home」,再進入用戶目錄,在用戶目錄下新建tcpclient.c)。
二、在tcpclient.c中編寫客戶端程序代碼並保存。將實驗一完成的tcpserver.c拷貝到與tcpclient.c同一目錄下。
三、在「終端」(「Applications」→「附件」→「終端」)中執行命令進入tcpserver.c和tcpclient.c所在目錄。
四、執行命令gcc –o tcpserver tcpserver.c生成可執行文件tcpserver。
五、執行命令./ tcpserver。
六、再開一個「終端」,進入tcpserver.c和tcpclient.c所在目錄,執行命令
gcc–o tcpclient tcpclient.c生成可執行文件tcpclient。
七、執行命令./ tcpclient 127.0.0.1。
八、觀察兩個「終端」出現的結果。
九、認真分析源代碼,體會如何編寫一個TCP客戶端程序。
#include<stdio.h> #include <stdlib.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> #define PORT 1234 #define MAXDATASIZE 100 int main(int argc, char *argv[]) { int sockfd, num; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in server; if (argc!=2) { printf("Usage:%s <IP Address>\n",argv[0]); exit(1); } if((he=gethostbyname(argv[1]))==NULL){ printf("gethostbyname()error\n"); exit(1); } if((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){ printf("socket()error\n"); exit(1); } bzero(&server,sizeof(server)); server.sin_family= AF_INET; server.sin_port = htons(PORT); server.sin_addr =*((struct in_addr *)he->h_addr); if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))==-1){ printf("connect()error\n"); exit(1); } if((num=recv(sockfd,buf,MAXDATASIZE,0)) == -1){ printf("recv() error\n"); exit(1); } buf[num-1]='\0'; printf("Server Message: %s\n",buf); close(sockfd); return 0; }