前言 socket编程现在几乎成了网络编程的代名词,关于这方面的书籍与资料更是不可胜数。比较好的可以推荐一下《Unix 网络编程 卷1:套接字联网API》。
1. TCP
TCP提供客户与服务器之间的连接(connection),TCP客户先与某个给定服务器之间建立一个连接,再跨该连接与那个服务器交换数据,然后终止这个连接。
1.1 TCP server
编程步骤:
socket→初始化struct sockaddr_in→bind→listen→[accept→send→recv]
tcp_server.c
- /*
-
* \brief
-
* tcp server
-
*/
-
#include <stdio.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <string.h>
-
#include <stdlib.h>
-
-
#define SERVPORT 8080
-
#define BACKLOG 10 // max numbef of client connection
-
#define MAXDATASIZE 100
-
-
int main(char argc, char *argv[])
-
{
-
int sockfd, client_fd, addr_size, recvbytes;
-
char rcv_buf[MAXDATASIZE], snd_buf[MAXDATASIZE];
-
char* val;
-
struct sockaddr_in server_addr;
-
struct sockaddr_in client_addr;
-
-
char IPdotdec[20];
-
-
/* create a new socket and regiter it to os .
-
* SOCK_STREAM means that supply tcp service,
-
* and must connect() before data transfort.
-
*/
-
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
-
{
-
perror("socket:");
-
exit(1);
-
}
-
-
/* setting server's socket */
-
server_addr.sin_family = AF_INET; // IPv4 network protocol
-
server_addr.sin_port = htons(SERVPORT);
-
server_addr.sin_addr.s_addr = INADDR_ANY; // auto IP detect
-
memset(&(server_addr.sin_zero),0, 8);
-
if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr))== -1)
-
{
-
perror("bind:");
-
exit(1);
-
}
-
-
/* watting for connection , and server permit to recive the requestion from sockfd */
-
if (listen(sockfd, BACKLOG) == -1) // BACKLOG assign thd max number of connection
-
{
-
perror("listen:");
-
exit(1);
-
}
-
-
while(1)
-
{
-
addr_size = sizeof(struct sockaddr_in);
-
-
/* accept the sockfd's connection,
-
* return an new socket and assign far host to client_addr
-
*/
-
if ((client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_size)) == -1)
-
{
-
/* Nonblocking mode */
-
perror("accept:");
-
continue;
-
}
-
-
/* network-digital to ip address */
-
inet_ntop(AF_INET, (void*)&client_addr, IPdotdec, 16);
-
printf("connetion from:%d : %s\n",client_addr.sin_addr, IPdotdec);
-
-
if (!fork())
-
{
-
/* child process handle with the client connection */
-
-
/* recive the client's data by client_fd */
-
if ((recvbytes = recv(client_fd, rcv_buf, MAXDATASIZE, 0)) == -1)
-
{
-
perror("recv:");
-
exit(1);
-
}
-
rcv_buf[recvbytes]='\0';
-
printf("recv:%s\n", rcv_buf);
-
-
-
*snd_buf='\0';
-
strcat(snd_buf, "welcome");
-
/* send the message to far-hosts by client_fd */
-
if (send(client_fd, snd_buf, strlen(snd_buf), 0) == -1)
-
{
-
perror("send:");
-
exit(1);
-
}
-
printf("send:%s\n", snd_buf);
-
-
close(client_fd);
-
exit(1);
-
}
-
-
close(client_fd);
-
}
-
-
return 0;
-
}
编译:
- gcc -g -o tcp_server tcp_server.c
1.2 TCP client
编程步骤:
socket→初始化struct sockaddr_in→connect→[recv→send]
tcp_client.c
- /*
-
* \brief
-
* tcp client
-
*/
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <netdb.h>
-
#include <string.h>
-
-
#define SERVPORT 8080
-
#define MAXDATASIZE 100
-
-
int main(int argc, char *argv[])
-
{
-
int sockfd, recvbytes;
-
char rcv_buf[MAXDATASIZE]; /*./client 127.0.0.1 hello */
-
char snd_buf[MAXDATASIZE];
-
struct hostent *host; /* struct hostent
-
* {
-
* char *h_name; // general hostname
-
* char **h_aliases; // hostname's alias
-
* int h_addrtype; // AF_INET
-
* int h_length;
-
* char **h_addr_list;
-
* };
-
*/
-
struct sockaddr_in server_addr;
-
-
if (argc < 3)
-
{
-
printf("Usage:%s [ip address] [any string]\n", argv[0]);
-
return 1;
-
}
-
-
*snd_buf = '\0';
-
strcat(snd_buf, argv[2]);
-
-
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
-
{
-
perror("socket:");
-
exit(1);
-
}
-
-
server_addr.sin_family = AF_INET;
-
server_addr.sin_port = htons(SERVPORT);
-
inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
-
memset(&(server_addr.sin_zero), 0, 8);
-
-
/* create the connection by socket
-
* means that connect "sockfd" to "server_addr"
-
*/
-
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
-
{
-
perror("connect");
-
exit(1);
-
}
-
-
/**/
-
if (send(sockfd, snd_buf, sizeof(snd_buf), 0) == -1)
-
{
-
perror("send:");
-
exit(1);
-
}
-
printf("send:%s\n", snd_buf);
-
-
if ((recvbytes = recv(sockfd, rcv_buf, MAXDATASIZE, 0)) == -1)
-
{
-
perror("recv:");
-
exit(1);
-
}
-
-
rcv_buf[recvbytes] = '\0';
-
printf("recv:%s\n", rcv_buf);
-
-
close(sockfd);
-
return 0;
-
}
编译:
- gcc -o -g tcp_client tcp_client.c
2. UDP
UDP提供无连接的(connectionless)服务,比如一个UDP客户可以创建一个套接字并发送一个数据报给一个给定的服务器,然后立即用同一个套接字发送另一个数据报给另一个服务器。同样地,一个UDP服务器可以用同一个UDP套接字从若干不同的客户接收数据报,每个客户一个数据报。
2.1 UDP server
编程步骤:
socket→初始化struct sockaddr_in→bind→[recvfrom→sendto]
udp_server.c
- #include <stdio.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <string.h>
-
#include <stdlib.h>
-
-
-
#define SERVPORT 8080
-
#define MAXDATASIZE 100
-
-
int main()
-
{
-
int sockfd, addr_size, recvbytes;
-
char rcv_buf[MAXDATASIZE], snd_buf[MAXDATASIZE];
-
char* val;
-
struct sockaddr_in server_addr;
-
-
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-
{
-
perror("socket:");
-
exit(1);
-
}
-
-
server_addr.sin_family = AF_INET;
-
server_addr.sin_port = htons(SERVPORT);
-
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
memset(&(server_addr.sin_zero), 0, 8);
-
-
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))==-1)
-
{
-
perror("bind:");
-
exit(1);
-
}
-
-
while(1)
-
{
-
addr_size = sizeof(struct sockaddr);
-
-
/* receive the data from "server_addr" by "sockfd" and store into "rcv_buf" */
-
if ((recvbytes = recvfrom(sockfd, rcv_buf, MAXDATASIZE, 0,
-
(struct sockaddr*)&server_addr, &addr_size)) == -1)
-
{
-
perror("recv:");
-
exit(1);
-
}
-
rcv_buf[recvbytes] = '\0';
-
printf("recv:%s : %s\n", inet_ntop(server_addr.sin_addr), rcv_buf);
-
-
*snd_buf = '\0';
-
strcat(snd_buf, "welcome");
-
-
/* send the data "snd_buf" to "server_addr" by "sockfd" */
-
if (sendto(sockfd, snd_buf, strlen(snd_buf), 0,
-
(struct sockaddr*)&server_addr, addr_size) == -1)
-
{
-
perror("send:");
-
exit(1);
-
}
-
printf("send:%s\n", snd_buf);
-
//exit(1);
-
}
-
close(sockfd);
-
return 0;
-
}
编译:
- gcc -g -o udp_server udp_server.c
2.2 UDP client
编程步骤:
socket→初始化struct sockaddr_in→[sendto→recvfrom]
udp_client.c
- #include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <netdb.h>
-
#include <string.h>
-
-
#define SERVPORT 8080
-
#define MAXDATASIZE 100
-
-
int main(int argc, char *argv[])
-
{
-
int server_sockfd, recvbytes,addr_size;
-
char rcv_buf[MAXDATASIZE]; /*./client 127.0.0.1 hello*/
-
char snd_buf[MAXDATASIZE];
-
struct hostent *host;
-
struct sockaddr_in server_addr;
-
-
if (argc < 3)
-
{
-
printf("Usage:%s [ip address] [any string]\n",argv[0]);
-
return 1;
-
}
-
*snd_buf = '\0';
-
strcat(snd_buf,argv[2]);
-
-
if ((server_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-
{
-
perror("socket:");
-
exit(1);
-
}
-
-
server_addr.sin_family=AF_INET;
-
server_addr.sin_port=htons(SERVPORT);
-
inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
-
memset(&(server_addr.sin_zero),0,8);
-
addr_size=sizeof(struct sockaddr);
-
-
/* send the data "snd_buf" to "server_addr" by server_sockfd */
-
if (sendto(server_sockfd,snd_buf,sizeof(snd_buf),0,
-
(struct sockaddr*)&server_addr,addr_size) == -1)
-
{
-
perror("send:");
-
exit(1);
-
}
-
printf("send:%s\n",snd_buf);
-
-
/* receive the data from "server_addr" by "server_sockfd" and store into rcv_buf */
-
if ((recvbytes=recvfrom(server_sockfd,rcv_buf,MAXDATASIZE,0,
-
(struct sockaddr*)&server_addr,&addr_size)) ==-1)
-
{
-
perror("recv:");
-
exit(1);
-
}
-
rcv_buf[recvbytes] = '\0';
-
printf("recv:%s\n",rcv_buf);
-
-
close(server_sockfd);
-
return 0;
-
}
编译:
- gcc -g -o udp_client udp_client.c
3. UDP multicast
有时候,本机不止有一张网卡,所以接收UDP组播的数据先要将本机指定的网卡地址加入组播组,才能接收到组播数据。
编程步骤:
socket-->setsockopt-->bind->setsockopt(本机网卡加入组播组)-->[recvfrom --> sendto]
udp_multicast_recv.c
- #include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
-
#define UDPMCASTPORT 1234
-
#define MAXDATASIZE 1024
-
-
-
-
int main(char argc, char *argv[])
-
{
-
int udp_sockfd, addr_size, recvbytes;
-
char rcv_buf[MAXDATASIZE];
-
-
struct sockaddr_in servaddr, clitaddr;
-
struct ip_mreq mreq;
-
-
char* pc_udpmcaddr = "225.1.1.31";
-
char* pc_udpmcport = "1234";
-
char* pc_localaddr = "192.168.1.73";
-
int i_reuse_socket;
-
-
-
if (argc != 3)
-
{
-
fprintf(stdout, "SYNTAX: ./udp_mcast_recv \n");
-
exit(1);
-
}
-
else
-
{
-
pc_udpmcaddr = argv[1];
-
pc_localaddr = argv[2];
-
}
-
-
memset(&servaddr, 0, sizeof(struct sockaddr_in));
-
memset(&clitaddr, 0, sizeof(struct sockaddr_in));
-
memset(&mreq, 0, sizeof(struct ip_mreq));
-
-
/* create socket */
-
if ((udp_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-
{
-
perror("socket:");
-
exit(1);
-
}
-
-
i_reuse_socket = 1;
-
if (setsockopt(udp_sockfd, SOL_SOCKET, SO_REUSEADDR, &i_reuse_socket, sizeof(int))== -1)
-
{
-
perror("setsockopt:");
-
exit(1);
-
}
-
-
servaddr.sin_family = AF_INET;
-
servaddr.sin_port = htons(UDPMCASTPORT);
-
-
if (!inet_aton(pc_udpmcaddr, &servaddr.sin_addr))
-
{
-
perror("inet_aton:");
-
exit(1);
-
}
-
if (bind(udp_sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr))==-1)
-
{
-
perror("bind:");
-
exit(1);
-
}
-
-
if (!inet_aton(pc_udpmcaddr, &mreq.imr_multiaddr))
-
{
-
perror("inet_aton:");
-
exit(1);
-
}
-
-
if (!inet_aton(pc_localaddr, &mreq.imr_interface))
-
{
-
perror("inet_aton:");
-
exit(1);
-
}
-
-
if (setsockopt(udp_sockfd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))==-1)
-
{
-
perror("setsockopt:");
-
exit(1);
-
}
-
-
addr_size = sizeof(struct sockaddr);
-
-
while(1)
-
{
-
if ((recvbytes = recvfrom(udp_sockfd, rcv_buf, MAXDATASIZE, 0,
-
(struct sockaddr*)&clitaddr, &addr_size)) == -1)
-
{
-
perror("recvfrom:");
-
exit(1);
-
}
-
rcv_buf[recvbytes] = '\0';
-
fprintf(stdout, "recvfrom:%s:%s", inet_ntoa(clitaddr.sin_addr), rcv_buf);
-
}
-
}
编译:
- gcc -g -o udp_multicast_recv udp_multicast_recv.c
阅读(1174) | 评论(0) | 转发(0) |