所謂套接字(Socket),就是對網(wǎng)絡(luò)中不同主機上的應(yīng)用進程之間進行雙向通信的端點的抽象。一個套接字就是網(wǎng)絡(luò)上進程通信的一端,提供了應(yīng)用層進程利用網(wǎng)絡(luò)協(xié)議交換數(shù)據(jù)的機制。從所處的地位來講,套接字上聯(lián)應(yīng)用進程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議進行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進行交互的接口 [1]? 。
套接字是通信的基石,是支持TCP/IP協(xié)議的路通信的基本操作單元??梢詫⑻捉幼挚醋鞑煌鳈C間的進程進行雙間通信的端點,它構(gòu)成了單個主機內(nèi)及整個網(wǎng)絡(luò)間的編程界面。套接字存在于通信域中,通信域是為了處理一般的線程通過套接字通信而引進的一種抽象概念。套接字通常和同一個域中的套接字交換數(shù)據(jù)(數(shù)據(jù)交換也可能穿越域的界限,但這時一定要執(zhí)行某種解釋程序),各種進程使用這個相同的域互相之間用Internet協(xié)議簇來進行通信?[3]??。
Socket(套接字)可以看成是兩個網(wǎng)絡(luò)應(yīng)用程序進行通信時,各自通信連接中的端點,這是一個邏輯上的概念。它是網(wǎng)絡(luò)環(huán)境中進程間通信的API(應(yīng)用程序編程接口),也是可以被命名和尋址的通信端點,使用中的每一個套接字都有其類型和一個與之相連進程。通信時其中一個網(wǎng)絡(luò)應(yīng)用程序?qū)⒁獋鬏數(shù)囊欢涡畔懭胨谥鳈C的 Socket中,該 Socket通過與網(wǎng)絡(luò)接口卡(NIC)相連的傳輸介質(zhì)將這段信息送到另外一臺主機的 Socket中,使對方能夠接收到這段信息。 Socket是由IP地址和端口結(jié)合的,提供向應(yīng)用層進程傳送數(shù)據(jù)包的機制?[2]??。
TCP/IP 是互聯(lián)網(wǎng)的基礎(chǔ), TCP代表傳輸控制協(xié)議,IP代表互聯(lián)網(wǎng)協(xié)議。目前有兩個版本IP,一個是32位地址的IPv4 和一個是128位的 IPv6 。而IPv4 是現(xiàn)如今使用最多的IP版本,也是這次討論的重點。
TCP/UDP對比
1. TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,即發(fā)送數(shù)據(jù)之前?????? 不需? 要建立連接
2.? TCP提供可靠的服務(wù)。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯,不丟失,不重復(fù),且按序到達;UDP盡最大努力交付,即不保證可靠交付
3.? TCP面向字節(jié)流,實際上是TCP把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流;UDP是面向報文的
UDP沒有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會使源主機的發(fā)送速率降低(對實時應(yīng)用很有用,如IP電話,實時視頻會議等)
4.? 每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信
5.? TCP首部開銷20字節(jié);UDP的首部開銷小,只有8個字節(jié)
6.? TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道
端口號作用
一臺擁有IP地址的主機可以提供許多服務(wù),比如Web服務(wù)、FTP服務(wù)、SMTP服務(wù)等
這些服務(wù)完全可以通過1個IP地址來實現(xiàn)。那么,主機是怎樣區(qū)分不同的網(wǎng)絡(luò)服務(wù)呢?顯然不能只靠IP地址,因為IP 地址與網(wǎng)絡(luò)服務(wù)的關(guān)系是一對多的關(guān)系。
實際上是通過“IP地址+端口號”來區(qū) 分不同的服務(wù)的。
端口提供了一種訪問通道,
服務(wù)器一般都是通過知名端口號來識別的。例如,對于每個TCP/IP實現(xiàn)來說,F(xiàn)TP服務(wù)器的TCP端口號都是21,每個Telnet服務(wù)器的TCP端口號都是23,每個TFTP(簡單文件傳送協(xié)議)服務(wù)器的UDP端口號都是69
字節(jié)序
字節(jié)序,即字節(jié)在電腦中存放時的序列與輸入(輸出)時的序列是先到的在前還是后到的在前。
字節(jié)序是指多字節(jié)數(shù)據(jù)在計算機內(nèi)存中存儲或者網(wǎng)絡(luò)傳輸時各字節(jié)的存儲順序。
1. 小端字節(jié)序Little?endian:將低序字節(jié)存儲在起始地址
2. 網(wǎng)絡(luò)字節(jié)序、大端字節(jié)序Big?endian:將高序字節(jié)存儲在起始地址
字節(jié)序轉(zhuǎn)換api
htons的功能:將一個無符號短整型數(shù)值轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序,即大端模式(big-endian)
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue); //返回網(wǎng)絡(luò)字節(jié)序的值
uint32_t htonl(uint32_t host32bitvalue); //返回網(wǎng)絡(luò)字節(jié)序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主機字節(jié)序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主機字節(jié)序的值
h代表host,n代表net,s代表short(兩個字節(jié)),l代表long(4個字節(jié)),
通過上面的4個函數(shù)可以實現(xiàn)主機字節(jié)序和網(wǎng)絡(luò)字節(jié)序之間的轉(zhuǎn)換。
有時可以用INADDR_ANY,INADDR_ANY指定地址讓操作系統(tǒng)自己獲取
Sockt服務(wù)器和客戶端的開發(fā)步驟(TCP)
服務(wù)端:
1.創(chuàng)建套接字
int socket(int domain, int type, int protocol);int socket(int domain, int type, int protocol);
2.為套接字添加信息
地址轉(zhuǎn)換API:
inet_aton是一個計算機函數(shù),功能是將一個字符串IP地址轉(zhuǎn)換為一個32位的網(wǎng)絡(luò)序列IP地址。如果這個函數(shù)成功,函數(shù)的返回值非零,如果輸入地址不正確則會返回零。使用這個函數(shù)并沒有錯誤碼存放在errno中,所以它的值會被忽略。
int inet_aton(const char* straddr,struct in_addr *addrp);
參數(shù)描述:
1 輸入?yún)?shù)string包含ASCII表示的IP地址。
2 輸出參數(shù)addr是將要用新的IP地址更新的結(jié)構(gòu)。
把字符串形式的“192.168.1.123”轉(zhuǎn)為網(wǎng)絡(luò)能識別的格式
char* inet_ntoa(struct in_addr inaddr);
把網(wǎng)絡(luò)格式的ip地址轉(zhuǎn)為字符串形式
3.監(jiān)聽網(wǎng)絡(luò)連接
4.監(jiān)聽到有客戶端接入,接受一個連接
5.數(shù)據(jù)交互
?6.關(guān)閉套接字,斷開連接
服務(wù)端代碼實現(xiàn)一:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int s_fd;
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1){
perror("socket");
exit(-1);
}
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8888);
//int inet_aton(const char *cp, struct in_addr *inp);
inet_aton ("192.168.193.128",&s_addr.sin_addr);
//inet_aton ("127.0.0.1",&s_addr.sin_addr);
//2.bind
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int c_fd = accept(s_fd,NULL,NULL);
//5.read
//6.write
printf("connect success\n");
while(1);
return 0;
}
與window端連接結(jié)果
服務(wù)端代碼實現(xiàn)二:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int s_fd;
int n_read;
char readBuf[128];
char *msg = "I get your connet";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8888);
//int inet_aton(const char *cp, struct in_addr *inp);
//inet_aton ("192.168.193.128",&s_addr.sin_addr);
inet_aton ("127.0.0.1",&s_addr.sin_addr);
//2.bind
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int clen = sizeof(struct sockaddr_in);
int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd==-1){
perror("accept");
}
printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));
//5.read
n_read = read(c_fd,readBuf,128);
if(n_read ==-1){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
//6.write
write(c_fd,msg,strlen(msg));
//printf("connect\n");
//while(1);
return 0;
}
連接運行:?
?客戶端connect函數(shù):
初步實現(xiàn)服務(wù)端與客戶端通信代碼:
?server.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int s_fd;
int n_read;
char readBuf[128];
char *msg = "I get your connet";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8888);
//int inet_aton(const char *cp, struct in_addr *inp);
//inet_aton ("192.168.193.128",&s_addr.sin_addr);
inet_aton ("127.0.0.1",&s_addr.sin_addr);
//2.bind
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int clen = sizeof(struct sockaddr_in);
int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd==-1){
perror("accept");
}
printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));
//5.read
n_read = read(c_fd,readBuf,128);
if(n_read ==-1){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
//6.write
write(c_fd,msg,strlen(msg));
//printf("connect\n");
//while(1);
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int c_fd;
int n_read;
char readBuf[128];
char *msg = "msg from client";
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(8888);
//int inet_aton(const char *cp, struct in_addr *inp);
//inet_aton ("192.168.193.128",&s_addr.sin_addr);
inet_aton ("127.0.0.1",&c_addr.sin_addr);
//2.connect
//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))==-1){
perror("connect");
exit(-1);
}
//3.send
write(c_fd,msg,strlen(msg));
//4.read
n_read = read(c_fd,readBuf,128);
if(n_read ==-1){
perror("read");
}else{
printf("get message from server:%d,%s\n",n_read,readBuf);
}
return 0;
}
運行連接:
?實現(xiàn)雙方聊天代碼:
server.c
#include <stdio.h>
#include <sys/types.h>/* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128];
char msg[128] = {0};
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc!=3){
printf("param is not good\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
//int inet_aton(const char *cp, struct in_addr *inp);
//inet_aton ("192.168.193.128",&s_addr.sin_addr);
inet_aton (argv[1],&s_addr.sin_addr);
//2.bind
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd==-1){
perror("accept");
}
printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));
if(fork()==0){
if(fork()==0){
while(1){
memset(msg,0,sizeof(msg));
printf("Iput: ");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
//5.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read ==-1){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
}
break;
}
}
return 0;
}
client.c文章來源:http://www.zghlxwxcb.cn/news/detail-729182.html
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int c_fd;
int n_read;
char readBuf[128];
char msg[128] = {0};
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc!=3){
printf("param is not good\n");
exit(-1);
}
//1.socket
//int socket(int domain, int type, int protocol);
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
//int inet_aton(const char *cp, struct in_addr *inp);
//inet_aton ("192.168.193.128",&s_addr.sin_addr);
inet_aton (argv[1],&c_addr.sin_addr);
//2.connect
//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))==-1){
perror("connect");
exit(-1);
}
while(1){
if(fork()==0){
while(1){
memset(msg,0,sizeof(msg));
printf("input: ");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
}else{
printf("get messgage from server : %d ,%s\n",n_read,readBuf);
}
}
}
//3.send
return 0;
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-729182.html
到了這里,關(guān)于網(wǎng)絡(luò)編程——socket服務(wù)端和客戶端(TCP)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!