TCP與UDP的區別
- 基於串連與無串連
- 對系統資源的要求(TCP較多,UDP少)
- UDP程式結構較簡單
- 流模式與資料報模式
TCP保證資料正確性,UDP可能丟包
TCP保證資料順序,UDP不保證
具體編程時的區別
- socket()的參數不同
- UDP Server不需要調用listen和accept
- UDP收發資料用sendto/recvfrom函數
- TCP:地址資訊在connect/accept時確定
UDP:在sendto/recvfrom函數中每次均 需指定地址資訊
- UDP:shutdown函數無效
部分滿足以下幾點要求時,應該採用UDP 面向資料報方式
- 網路資料大多為短訊息
- 擁有大量Client
- 對資料安全性無特殊要求
- 網路負擔非常重,但對響應速度要求高
例子:ICQ、ping
伺服器程式流程(多進程):
- 程式初始化
- 填寫本機地址資訊
- 綁定並監聽一個固定的連接埠
- 收到Client的串連後建立一個socket串連
- 產生一個新的進程與Client進行通訊和資訊處理
- 子通訊結束後中斷與Client的串連
用戶端程式流程:
- 程式初始化
- 填寫伺服器位址資訊
- 串連伺服器
- 與伺服器通訊和資訊處理
- 通訊結束後中斷連線
伺服器代碼
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 3490 /* 監聽的連接埠 */
#define BACKLOG 10 /* listen的請求接收隊列長度 */
int main() {
int sockfd, new_fd; /* 監聽連接埠,資料連接埠 */
struct sockaddr_in sa; /* 自身的地址資訊 */
struct sockaddr_in their_addr; /* 串連對方的地址資訊 */
int sin_size;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
sa.sin_family = AF_INET;
sa.sin_port = htons(MYPORT); /* 網路位元組順序 */
sa.sin_addr.s_addr = INADDR_ANY; /* 自動填本機IP */
bzero(&(sa.sin_zero), 8); /* 其餘部分置0 */
if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
/* 主迴圈 */
while(1) {
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size));
if (new_fd == -1) {
perror("accept");
continue;
}
printf("Got connection from %s/n", inet_ntoa(their_addr.sin_addr));
if (fork() == 0) {
/* 子進程 */
if (send(new_fd, "Hello, world!/ n", 14, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd);
/*清除所有子進程 */
while(waitpid(-1,NULL,WNOHANG) > 0);
}
}
用戶端代碼
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3490 /* Server的連接埠 */
#define MAXDATASIZE 100 /*一次可以讀的最大位元組數 */
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct hostent *he; /* 主機資訊 */
struct sockaddr_in their_addr; /* 對方地址資訊 */
if (argc != 2) {
fprintf(stderr,"usage: client hostname/n");
exit(1);
}
/* get the host info */
if ((he=gethostbyname(argv[1])) == NULL) {
/* 注意:擷取DNS資訊時,顯示出錯需要用herror而不是perror */
herror("gethostbyname");
exit(1);
}
if ((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT); /* short, NBO */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* 其餘部分設成0 */
if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
perror("connect");
exit(1);
}
if ((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==-1) {
perror("recv");
exit(1);
}
buf[numbytes] = '/0';
printf("Received: %s",buf);
close(sockfd);
return 0;
}
伺服器程式流程(單進程):
- 程式初始化
- 填寫本機地址資訊
- 綁定一個固定的連接埠
- 收到Client的資料報後進行處理與通訊
- 通訊結束後中斷連線
用戶端程式流程:
- 程式初始化
- 填寫伺服器位址資訊
- 串連伺服器
- 與伺服器通訊和資訊處理
- 通訊結束後中斷連線
UDP方式下伺服器與用戶端程式差別不大,僅第三步不同。
伺服器
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 3490 /* 監聽連接埠 */
void main()
{
int sockfd; /* 資料連接埠 */
struct sockaddr_in my_addr; /* 自身的地址資訊 */
struct sockaddr_in their_addr; /* 串連對方的地址資訊 */
int sin_size, retval;
char buf[128];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT); /* 網路位元組順序 */
my_addr.sin_addr.s_addr = INADDR_ANY; /* 自動填本機IP */
bzero(&(my_addr.sin_zero), 8); /* 其餘部分置0 */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) {
perror("bind");
exit(1);
}
/* 主迴圈 */
while(1) {
retval = recvfrom(sockfd, buf, 128, 0, (struct sockaddr *)&their_addr, &sin_size);
printf("Received datagram from %s/n",inet_ntoa(their_addr.sin_addr));
if (retval == 0) {
perror (“recvfrom");
close(sockfd);
break;
}
retval = sendto(sockfd, buf, 128, 0, (struct sockaddr *)&their_addr, sin_size);
}
}
用戶端
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3490 /* Server的連接埠 */
#define MAXDATASIZE 100 /*一次可以讀的最大位元組數 */
int main(int argc, char *argv[])
{
int sockfd, numbytes, sin_size;
char buf[MAXDATASIZE] = “Hello, world!”;
struct hostent *he; /* 主機資訊 */
struct sockaddr_in their_addr; /* 對方地址資訊 */
if (argc != 2) {
fprintf(stderr,"usage: client hostname/n");
exit(1);
}
/* get the host info */
if ((he=gethostbyname(argv[1])) == NULL) {
herror("gethostbyname");
exit(1);
}
if ((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT); /* short, NBO */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* 其餘部分設成0 */
numbytes = sendto(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&their_addr,sizeof(their_addr));
if (numbytes == -1) {
perror(“sendto");
exit(1);
}
printf(“Send: %s",buf);
numbytes = recvfrom(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&their_addr, &sin_size);
if (numbytes == -1) {
perror("recvfrom");
exit(1);
}
buf[numbytes] = '/0';
printf("Received: %s",buf);
close(sockfd);
return 0;
} //轉載出處:: http://www.cnblogs.com/chenxizhang/archive/2009/04/14/1435777.html