tcpsvr:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define LY_ERR printf
void accept_handle(int connfd, struct sockaddr_in peeraddr);
int main(int argc, const char *argv[])
{
int sockfd, connfd;
struct sockaddr_in seraddr, peeraddr;
socklen_t addrlen;
if (argc != 2) {
printf("Usage: %s <port>\n", argv[0]);
return -1;
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
LY_ERR("socket: %s\n", strerror(errno));
return -1;
}
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (int[]){1}, sizeof(int));
seraddr.sin_family = AF_INET;
seraddr.sin_port = ntohs(atoi(argv[1]));
seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr))) {
LY_ERR("bind: %s\n", strerror(errno));
return -1;
}
#define MAX_CONN (10)
if (listen(sockfd, MAX_CONN) < 0) {
LY_ERR("listen: %s\n", strerror(errno));
return -1;
}
addrlen = sizeof(struct sockaddr);
for (;;) {
connfd = accept(sockfd, (struct sockaddr *)(&peeraddr), &addrlen);
if (connfd < 0) {
LY_ERR("accept: %s\n", strerror(errno));
continue;
}
accept_handle(connfd, peeraddr);
}
return 0;
}
void accept_handle(int connfd, struct sockaddr_in peeraddr)
{
char buf1[32] = "Hello, welcome to server!";
char buf[32];
printf("Receive request from %s, port %d\n",
inet_ntop(AF_INET, &peeraddr.sin_addr, buf, sizeof(buf)),
ntohs(peeraddr.sin_port));
if (send(connfd, buf1, sizeof(buf1), 0) < 0) {
close(connfd);
return;
}
close(connfd);
}
tcpcli:
/*
* tcpclient.c - A simple TCP client
* usage: tcpclient <host> <port>
*/
#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 <netdb.h>
#include <errno.h>
#include <poll.h>
#define BUFSIZE 1024
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char **argv)
{
int sockfd, portno, n;
struct sockaddr_in serveraddr, cli;
struct hostent *server;
char *hostname;
char buf[BUFSIZE];
/* check command line arguments */
if (argc != 3) {
fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);
/* socket: create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
int enable = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
#if 1
/* 客户端也是可以绑定某个端口的 */
bzero((char *)&cli, sizeof(cli));
cli.sin_family = AF_INET;
cli.sin_port = ntohs(3307);
cli.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&cli, sizeof(struct sockaddr))) {
printf("bind: %s\n", strerror(errno));
return -1;
}
#endif
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(0);
}
/* build the server's Internet address */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
/* connect: create a connection with the server */
if (connect(sockfd, (const sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {
printf("errno = %d\n", errno);
error("ERROR connecting");
}
printf("conn success!");
/* print the server's reply */
bzero(buf, BUFSIZE);
n = read(sockfd, buf, 4);
if (n < 0) {
error("ERROR reading from socket");
}
n = read(sockfd, buf+4, BUFSIZE-4);
if (n < 0) {
error("ERROR reading from socket");
}
printf("Echo from server: %s, %d\n", buf, n);
close(sockfd);
return 0;
}
TCP Client 这里调用了两次 read 是为了和 udp 的做一个对比。TCP 这里,server发一次, client read 两次会正常返回, 程序正常结束(前提是 svr 发送的数据长度 >4).
udpsvr:
/*
* * udpserver.c - A simple UDP echo server
* * usage: udpserver <port>
* */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
/*
* * error - wrapper for perror
* */
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv) {
int sockfd; /* socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client's address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
struct hostent *hostp; /* client host info */
char buf[BUFSIZE]; /* message buf */
char *hostaddrp; /* dotted decimal host addr string */
int optval; /* flag value for setsockopt */
int n; /* message byte size */
/*
* * check command line arguments
* */
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);
/*
* * socket: create the parent socket
* */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* setsockopt: Handy debugging trick that lets
* * us rerun the server immediately after we kill it;
* * otherwise we have to wait about 20 secs.
* * Eliminates "ERROR on binding: Address already in use" error.
* */
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* * build the server's Internet address
* */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)portno);
/*
* * bind: associate the parent socket with a port
* */
if (bind(sockfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
/*
* * main loop: wait for a datagram, then echo it
* */
clientlen = sizeof(clientaddr);
while (1) {
/*
* * recvfrom: receive a UDP datagram from a client
* */
bzero(buf, BUFSIZE);
n = recvfrom(sockfd, buf, 3, 0,
(struct sockaddr *) &clientaddr, &clientlen);
if (n < 0)
error("ERROR in recvfrom");
n = recvfrom(sockfd, buf + 3, (BUFSIZE - 3), 0,
(struct sockaddr *) &clientaddr, &clientlen);
if (n < 0)
error("ERROR in recvfrom");
/*
* * gethostbyaddr: determine who sent the datagram
* */
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
printf("server received datagram from %s (%s)\n",
hostp->h_name, hostaddrp);
printf("server received %d/%d bytes: %s\n", strlen(buf), n, buf);
/*
* * sendto: echo the input back to the client
* */
n = sendto(sockfd, buf, strlen(buf), 0,
(struct sockaddr *) &clientaddr, clientlen);
if (n < 0)
error("ERROR in sendto");
}
}
Udp Svr 里面调用了两次 readfrom!!!
udpcli:
/*
* * udpclient.c - A simple UDP client
* * usage: udpclient <host> <port>
* */
#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 <netdb.h>
#define BUFSIZE 1024
/*
* * error - wrapper for perror
* */
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char **argv) {
int sockfd, portno, n;
int serverlen;
struct sockaddr_in serveraddr;
struct hostent *server;
char *hostname;
char buf[BUFSIZE];
/* check command line arguments */
if (argc != 3) {
fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);
/* socket: create the socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* gethostbyname: get the server's DNS entry */
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(0);
}
/* build the server's Internet address */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
/* get a message from the user */
bzero(buf, BUFSIZE);
printf("Please enter msg: ");
fgets(buf, BUFSIZE, stdin);
/* send the message to the server */
serverlen = sizeof(serveraddr);
n = sendto(sockfd, buf, strlen(buf), 0, (const struct sockaddr *)(&serveraddr), serverlen);
if (n < 0)
error("ERROR in sendto");
serverlen = sizeof(serveraddr);
n = sendto(sockfd, buf, strlen(buf), 0, (const struct sockaddr *)(&serveraddr), serverlen);
if (n < 0)
error("ERROR in sendto");
/* print the server's reply */
n = recvfrom(sockfd, buf, strlen(buf), 0, (struct sockaddr *)(&serveraddr), &serverlen);
if (n < 0)
error("ERROR in recvfrom");
printf("Echo from server: %s", buf);
return 0;
}
udp 这里调用了两次 sendto, 如果只调用一次 sendto, 那么 udp srv 就会阻塞在第二个 readfrom 即便你发送的数据长度大于 3 字节.
udp 的输入与输出:
./server 10003
server received datagram from localhost (127.0.0.1)
server received 14/11 bytes: 1231234567890
./client 127.0.0.1 10003
Please enter msg: 1234567890
Echo from server: 12312345678
具体原理可以参考:
https://my.oschina.net/tsh/blog/995626