socket編程
-
socket編程的基本函數(shù)有socket()凿蒜、bind()禁谦、listen()、accept()废封、send()州泊、sendto()、recv()以及recvfrom()等漂洋,其中根據(jù)客戶端還是服務(wù)端遥皂,或者根據(jù)使用TCP協(xié)議還是UDP協(xié)議,這些函數(shù)的調(diào)用流程都有所區(qū)別刽漂。
1.socket():該函數(shù)用于建立一個(gè)socket連接(即創(chuàng)建一個(gè)套接字)演训,可指定socket類型等信息。在建立了socket連接之后贝咙,可對(duì)sockaddr或sockaddr_in結(jié)構(gòu)進(jìn)行初始化样悟,以保存所建立的socket地址信息。
2.bind():該函數(shù)是用于將socket套接字與本地IP地址及端口號(hào)綁定庭猩,若綁定其他IP地址則不能成功窟她。另外,它主要用于服務(wù)器端蔼水,而在客戶端則無(wú)必要震糖。
3.listen():在服務(wù)端程序成功建立套接字和與地址進(jìn)行綁定之后,還需要準(zhǔn)備在該套接字上接收新的連接請(qǐng)求趴腋。此時(shí)調(diào)用listen()函數(shù)來(lái)創(chuàng)建一個(gè)等待隊(duì)列吊说,在其中存放未處理的客戶端連接請(qǐng)求。
4.accept():服務(wù)端程序調(diào)用listen()函數(shù)創(chuàng)建等待隊(duì)列之后于样,調(diào)用accept()函數(shù)等待并接收客戶端的連接請(qǐng)求疏叨。它通常從由listen()所創(chuàng)建的等待隊(duì)列中取出第一個(gè)未處理的連接請(qǐng)求潘靖。
5.connect():該函數(shù)在TCP中是用于bind()的之后的client端穿剖,用于與服務(wù)器端建立連接。
6.send()和recv():這兩個(gè)函數(shù)分別用于發(fā)送和接收數(shù)據(jù)卦溢,用在TCP中糊余。
7.sendto()和recvfrom():這兩個(gè)函數(shù)的作用與send()和recv()函數(shù)類似,可以用在TCP和UDP中单寂。當(dāng)用在TCP時(shí)贬芥,后面的幾個(gè)與地址有關(guān)參數(shù)不起作用,函數(shù)作用等同于send()和recv()宣决;主要用在UDP時(shí)蘸劈,這兩個(gè)函數(shù)可以自動(dòng)尋找指定地址并進(jìn)行連接。
代碼實(shí)戰(zhàn)
/*server.c*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 4321
#define BUFFER_SIZE 1024
#define MAX_QUE_CONN_NM 5
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes,sendbytes;
int sockfd, client_fd;
char buf[BUFFER_SIZE];
/*建立socket連接*/
if ((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1)
{
perror("socket");
exit(1);
}
printf("Socket id = %d\n",sockfd);
/*設(shè)置sockaddr_in 結(jié)構(gòu)體中相關(guān)參數(shù)*/
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_sockaddr.sin_zero), 8);
int i = 1;/* 允許重復(fù)使用本地地址與套接字進(jìn)行綁定 */
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
/*綁定函數(shù)bind()*/
if (bind(sockfd, (struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
printf("Bind success!\n");
/*調(diào)用listen()函數(shù)尊沸,創(chuàng)建未處理請(qǐng)求的隊(duì)列*/
if (listen(sockfd, MAX_QUE_CONN_NM) == -1)
{
perror("listen");
exit(1);
}
printf("Listening....\n");
/*調(diào)用accept()函數(shù)威沫,等待客戶端的連接*/
sin_size=sizeof(struct sockaddr);
if ((client_fd = accept(sockfd,
(struct sockaddr *)&client_sockaddr, &sin_size)) == -1)
{
perror("accept");
exit(1);
}
/*調(diào)用recv()函數(shù)接收客戶端的請(qǐng)求*/
while(1)
{
memset(buf , 0, sizeof(buf));
if ((recvbytes = recv(client_fd, buf, BUFFER_SIZE, 0)) == -1)
{
perror("recv");
exit(1);
}
printf("Received a message: %s\n", buf);
}
close(sockfd);
exit(0);
}
/*client.c*/
#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 8888
#define BUFFER_SIZE 1024
int main(int argc, char *argv[])
{
int sockfd,sendbytes;
char buf[BUFFER_SIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if(argc < 3)
{
fprintf(stderr,"USAGE: ./client Hostname(or ip address) Text\n");
exit(1);
}
/*地址解析函數(shù)*/
if ((host = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname");
exit(1);
}
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", argv[2]);
//sprintf(buf, "%s", "This is client,I want to connect!");
/*創(chuàng)建socket*/
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
/*設(shè)置sockaddr_in 結(jié)構(gòu)體中相關(guān)參數(shù)*/
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero), 8);
/*調(diào)用connect函數(shù)主動(dòng)發(fā)起對(duì)服務(wù)器端的連接*/
if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))== -1)
{
perror("connect failed!\n");
exit(1);
}
/*發(fā)送消息給服務(wù)器端*/
if ((sendbytes = send(sockfd, buf, strlen(buf), 0)) == -1)
{
perror("send");
exit(1);
}
memset(buf , 0, sizeof(buf));
close(sockfd);
exit(0);
}