1、 tcp程序设计
代码1 server:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define portnumber 3333
int main(int argc, char *argv[])
{
int sockfd, new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
int nbytes;
char buffer[1024];
//AF_INET: IPV4, SOCK_STREAM: TCP
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket error:%s\n\a", strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(portnumber);
if(bind(sockfd, (struct sockaddr *) (&server_addr), sizeof(structsockaddr)) == -1)
{
fprintf(stderr, "Bind error: %s\n\a", strerror(errno));
exit(1);
}
if(listen(sockfd, 5) == -1)
{
fprintf(stderr, "Listen error: %s\n\a", strerror(errno));
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)(&client_addr),&sin_size)) == -1)
{
fprintf(stderr, "Accept error:%s\n\a", strerror(errno));
exit(1);
}
fprintf(stderr, "Server get connection from %s\n",(char*)inet_ntoa(client_addr.sin_addr));
if((nbytes = read(new_fd, buffer, 1024)) == -1)
{
fprintf(stderr, "Read Error: %s\n", strerror(errno));
exit(1);
}
buffer[nbytes] = '\0';
printf("Server received %s\n", buffer);
close(new_fd);
}
close(sockfd);
return 0;
}
代码2 client:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define portnumber 3333
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
if(argc != 2)
{
fprintf(stderr, "Usage: %s hostname \a\n", argv[0]);
exit(1);
}
if((host = gethostbyname(argv[1])) == NULL)
{
fprintf(stderr, "Gethostname Error:%s\a\n", strerror(errno));
exit(1);
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket Error: %s\a\n", strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portnumber);
server_addr.sin_addr = *((struct in_addr *) host->h_addr);
if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr))== -1)
{
fprintf(stderr, "Connect Error: %s\a\n", strerror(errno));
exit(1);
}
printf("Please input char: \n");
fgets(buffer, 1024, stdin);
write(sockfd, buffer, strlen(buffer));
close(sockfd);
return 0;
}
Makefile:
CC = gcc
CURTDIR = $(shell pwd)
TARGET = tcp_client
#TARGET = tcp_server
%.o:%.c
$(CC)-c $(EXTRAFLAGS) $< -o $@
%.o:%.S
$(CC)-c $(EXTRAFLAGS) $< -o $@
.PHONY: all clean
$(TARGET): $(TARGET).o
$(CC) -o $@ $^
clean:
rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$make
gcc -c tcp_server.c -o tcp_server.o
gcc -o tcp_server tcp_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$ls
Makefile tcp_client.c tcp_server tcp_server.c tcp_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$make
gcc -c tcp_client.c -o tcp_client.o
gcc -o tcp_client tcp_client.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$ls
Makefile tcp_client tcp_client.c tcp_client.o tcp_server tcp_server.c tcp_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_client 192.0.4.87
Please input char:
hello mytcp
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_client 192.0.4.87
Please input char:
I am back!
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_server
Server get connection from 192.0.4.87
Server received hello mytcp
Server get connection from 192.0.4.87
Server received I am back!
总结:当没有client连接上时,server程序阻塞在accept函数上,等待连接。当有client连接上来时,阻塞在read函数上,等待读取消息。Client发送一条消息后结束,server读出消息打印,继续等待新的连接
2、 udp程序设计
代码1 server:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define portnumber 3333
#define MAX_MSG_SIZE 1024
void udps_respon(int sockfd)
{
struct sockaddr_in addr;
int addrlen, n;
char msg[MAX_MSG_SIZE];
while(1)
{
bzero(msg, sizeof(msg));
addrlen = sizeof(struct sockaddr);
n = recvfrom(sockfd, msg, MAX_MSG_SIZE, 0, (struct sockaddr *)&addr,&addrlen);
msg[n] = 0;
fprintf(stdout, "Server had received %s\n", msg);
}
}
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in addr;
//AF_INET: IPV4, SOCK_DGRAM: UDP
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
fprintf(stderr, "Socket error: %s\n\a", strerror(errno));
exit(1);
}
bzero(&addr, sizeof(struct sockaddr_in));
addr.sin_family= AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(portnumber);
if(bind(sockfd, (struct sockaddr *) (&addr), sizeof(structsockaddr)) == -1)
{
fprintf(stderr, "Bind error: %s\n\a", strerror(errno));
exit(1);
}
udps_respon(sockfd);
close(sockfd);
return 0;
}
代码2 client:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define portnumber 3333
#define MAX_BUF_SIZE 1024
void udpc_requ(int sockfd, const structsockaddr_in *addr, int len)
{
char buffer[MAX_BUF_SIZE];
int n;
while(1)
{
printf("Please input char: \n");
fgets(buffer, MAX_BUF_SIZE, stdin);
sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr*)addr, len);
bzero(buffer, MAX_BUF_SIZE);
}
}
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in addr;
if(argc != 2)
{
fprintf(stderr, "Usage: %s hostname \a\n", argv[0]);
exit(1);
}
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
fprintf(stderr, "Socket Error: %s\a\n", strerror(errno));
exit(1);
}
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(portnumber);
if(inet_aton(argv[1], &addr.sin_addr) < 0)
{
fprintf(stderr, "IP error:%s\n", strerror(errno));
exit(1);
}
udpc_requ(sockfd, &addr, sizeof(struct sockaddr_in));
close(sockfd);
return 0;
}
Makefile:
CC = gcc
CURTDIR = $(shell pwd)
TARGET = udp_client
#TARGET = udp_server
%.o:%.c
$(CC)-c $(EXTRAFLAGS) $< -o $@
%.o:%.S
$(CC)-c $(EXTRAFLAGS) $< -o $@
.PHONY: all clean
$(TARGET): $(TARGET).o
$(CC) -o $@ $^
clean:
rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$make
gcc -c udp_server.c -o udp_server.o
gcc -o udp_server udp_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$make
gcc -c udp_client.c -o udp_client.o
gcc -o udp_client udp_client.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$./udp_client 192.0.4.87
Please input char:
hello myudp
Please input char:
good-buy
Please input char:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$./udp_server
Server had received hello myudp
Server had received good-buy
总结:当没有client连接上时,server处于阻塞状态,阻塞在recvfrom函数上。当有client连接上来时。Client发送一条消息后结束,server读出消息打印。
3、 并发服务器设计
代码1 server:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
#define portnumber 3333
void *thr_fn(void *arg)
{
int size, j;
char recv_buff[1024];
int *parg = (int *)arg;
int new_fd = *parg;
printf("new_fd = %d\n", new_fd);
while((size = read(new_fd, recv_buff, 1024)) > 0)
{
if(recv_buff[0] == '@')
break;
printf("Message from client(%d): %s\n", size, recv_buff);
for(j = 0; j < size; j++)
{
recv_buff[j] = toupper(recv_buff[j]);
}
write(new_fd, recv_buff, size);
memset(recv_buff, 0, sizeof(recv_buff));
}
close(new_fd);
return NULL;
}
int main(int argc, char *argv[])
{
int listen_sockfd;
int com_fd;
int i;
static char recv_buff[1024];
int len;
int port;
pthread_t tid;
socklen_t clt_addr_len;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
if(argc != 2)
{
printf("Usage: %s port\n", argv[0]);
return 1;
}
port = atoi(argv[1]);
if((listen_sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket error: %s\n\a", strerror(errno));
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if(bind(listen_sockfd, (struct sockaddr *) (&server_addr),sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Bind error: %s\n\a", strerror(errno));
close(listen_sockfd);
exit(1);
}
if(listen(listen_sockfd, 5) == -1)
{
fprintf(stderr, "Listen error: %s\n\a", strerror(errno));
close(listen_sockfd);
exit(1);
}
while(1)
{
len = sizeof(client_addr);
com_fd = accept(listen_sockfd, (struct sockaddr*)&client_addr,&len);
if(com_fd < 0)
{
if(errno == EINTR)
{
continue;
}
else
{
perror("cannot acceptclient connect request\n");
close(listen_sockfd);
return 1;
}
}
printf("com_fd = %d\n", com_fd);
if((pthread_create(&tid, NULL, thr_fn, &com_fd)) == -1)
{
perror("pthread_create error");
close(listen_sockfd);
close(com_fd);
return 1;
}
}
return 0;
}
代码2 client:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#define portnumber 3333
int main(int argc, char *argv[])
{
int connect_fd;
int ret;
char snd_buf[1024];
int i;
int port;
int len;
static struct sockaddr_in server_addr;
if(argc != 3)
{
fprintf(stderr, "Usage: %s ip \a\n", argv[0]);
exit(1);
}
port = atoi(argv[2]);
if((connect_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket Error: %s\a\n", strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(port);
if(connect(connect_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Connect Error: %s\a\n", strerror(errno));
exit(1);
}
memset(snd_buf, 0, 1024);
while(1)
{
printf("input message: \n");
memset(snd_buf, 0, sizeof(snd_buf));
fgets(snd_buf, 1024, stdin);
len = strlen(snd_buf);
write(connect_fd, snd_buf, len);
len = read(connect_fd, snd_buf, len);
if(len > 0)
printf("Message from server: %s\n", snd_buf);
if(snd_buf[0] == '@')
break;
}
close(connect_fd);
return 0;
}
Makefile:
CC = gcc
CURTDIR = $(shell pwd)
#TARGET = thread_client
TARGET = thread_server
%.o:%.c
$(CC)-c $(EXTRAFLAGS) $< -o $@
%.o:%.S
$(CC)-c $(EXTRAFLAGS) $< -o $@
.PHONY: all clean
$(TARGET): $(TARGET).o
$(CC) -o $@ $^ -lpthread
clean:
rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$make
gcc -c thread_server.c -o thread_server.o
gcc -o thread_server thread_server.o -lpthread
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$ls
Makefile thread_client.c thread_server thread_server.c thread_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$make
gcc -c thread_client.c -o thread_client.o
gcc -o thread_client thread_client.o -lpthread
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$ls
Makefile thread_client thread_client.c thread_client.o thread_server thread_server.c thread_server.o
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222
input message:
hello, i am the 1st
Message from server: HELLO, I AM THE 1ST
input message:
@
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222
input message:
hello, i am the 1st, i am back
Message from server: HELLO, I AM THE 1ST, IAM BACK
input message:
@
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222
input message:
hi, i am the 2nd
Message from server: HI, I AM THE 2ND
input message:
@
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_server 2222
com_fd = 4
new_fd = 4
Message from client(20): hello, i am the1st
com_fd = 5
new_fd = 5
Message from client(17): hi, i am the 2nd
com_fd = 6
new_fd = 6
Message from client(31): hello, i am the1st, i am back
总结:并发服务器由于使用了多线程或者多进程,所以能同事接受多个客户端的连接。循环服务器只有在一个连接断掉之后才能接受另一个连接,因为服务器进程正在执行对客户端的消息收发不能继续循环去接受新的连接。