简单版本
(1) 创建套接字socket
int socket(int domain, int type, int protocol);
参数 :domain指定通信域,这里使用AF_INET,
type指定传输数据的类型,这里使用流式数据类型SOCK_STREAM,
protocol指定一个与套接字一起使用的协议,也可以给0。
返回值:该函数成功则返回文件描述符,失败返回-1。
(2)
通常,在SOCK_STREAM套接字可能接收连接之前通常需要使用bind()分配本地地址
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
参数 :sockfd,文件描述符sockfd引用的套接字socket,
const struct sockaddr *addr,该结构体中保存着ip地址与端口号分配给sockfd
socklen_t addrlen,结构体大小
返回值:该函数成功则返回0,失败返回-1。
int listen(int sockfd, int backlog);
参数 :sockfd,文件描述符sockfd引用的套接字socket,
backlog参数定义sockfd的挂起连接队列可能增长的最大长度。这里给10。
返回值:该函数成功则返回0,失败返回-1
(4) 接收链接,当客户端向服务器发送请求时服务器用accept()返回并接收这个链接。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数 :sockfd,文件描述符sockfd引用的套接字socket,
struct sockaddr *addr
,该结构体中保存着client端的ip地址与端口号。
socklen_t *addrlen,必须初始化,保存着结构体大小。
返回值:该函数成功则返回0,失败返回-1
这些全部搞定之后就可以开始进行数据传送了,因为是流式数据类型,所以可以用read和write进行数据读写。
下面是简单的tcp服务器代码以及客户端代码。
server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&server,sizeof(server))< 0){
perror("bind");
exit(3);
}
printf("bind succes\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
while(1)
{
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);
if(s > 0)
{
buf[s]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
}
return 0;
}
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&server,sizeof(server))< 0){
perror("bind");
exit(3);
}
printf("bind succes\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
while(1)
{
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);
if(s > 0)
{
buf[s]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
}
return 0;
}
client.c
客户端需要使用connect()链接服务器。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数 :sockfd,文件描述符sockfd引用的套接字socket,
struct sockaddr *addr
,该结构体中保存着需要连接的服务器端的ip地址与端口号。
socklen_t addrlen,结构体大小。
返回值:该函数成功则返回0,失败返回-1
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[])
{
if(argc!= 3){
printf("usage:%s,ip port \n",argv[0]);
return 1;
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("sock");
exit(2);
}
struct sockaddr_in client;
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(argv[1]);
client.sin_port = htons(atoi(argv[2]));
int ret = connect(sock,(struct sockaddr*)&client,sizeof(client));
if(ret< 0){
perror("connect");
exit(3);
}
printf("connect succes!\n");
while(1)
{
char buf[1024];
printf("PLease Enter# ");
fflush(stdout);
ssize_t s = read(0, buf ,sizeof(buf)-1);
if(s > 0)
{
buf[s-1]= 0;
write(sock,buf,strlen(buf));
ssize_t k=read(sock,buf,sizeof(buf)-1);
if(k > 0){
buf[k = 0];
printf("server echo# %s\n",buf);}
}
}
close(sock);
return 0;
}
多进程版本
多进程版本整体与简单版本一致,只不过将读写任务交给孙子进程去做,爷爷进程监听,
父进程创建子进程后自己退出,爷爷进程回收父进程然后监听。
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))< 0){
perror("bind");
exit(3);
}
printf("bind succes!\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
pid_t id = fork();
if(id < 0){
perror("fork");
close(new_sock);
continue;
}else if(id == 0){//child
close(listen_sock);
if(fork() > 0){
exit(0);
}
while(1){
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);//有bug
if(s > 0){
buf[s-1]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
exit(1);
}else{//father
close(new_sock);
waitpid(id,NULL,0);
}
}
return 0;
}
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))< 0){
perror("bind");
exit(3);
}
printf("bind succes!\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
pid_t id = fork();
if(id < 0){
perror("fork");
close(new_sock);
continue;
}else if(id == 0){//child
close(listen_sock);
if(fork() > 0){
exit(0);
}
while(1){
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);//有bug
if(s > 0){
buf[s-1]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
exit(1);
}else{//father
close(new_sock);
waitpid(id,NULL,0);
}
}
return 0;
}
多线程版本
创建一个线程去读写,然后将线程设置成分离状态
server.c
#include<stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))< 0){
perror("bind");
exit(3);
}
printf("bind succes!\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
void *request(void* arg)
{
int new_sock = (int)arg;
while(1){
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);//有bug
if(s > 0)
{
buf[s]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
return (void*)0;
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
//version 3
pthread_t id;
pthread_create(&id, NULL, request, (void*)new_sock);
pthread_detach(id);
}
return 0;
}
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
int startup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock< 0){
perror("socket");
exit(2);
}
printf("socket succes! sock= %d;\n",sock);
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))< 0){
perror("bind");
exit(3);
}
printf("bind succes!\n");
if(listen(sock,10)< 0)
{
perror("listen");
exit(4);
}
return sock;
}
void usage(char* s)
{
printf("usage: %s [loacl_ip] [loacl_port]\n",s);
}
void *request(void* arg)
{
int new_sock = (int)arg;
while(1){
char buf[1024];
ssize_t s = read(new_sock,buf,sizeof(buf)-1);//有bug
if(s > 0)
{
buf[s]= 0;
printf("client# %s\n",buf);
write(new_sock,buf,strlen(buf));
}else if(s==0){
printf("clinet is quit!\n");
break;
}else{
perror("read");
break;
}
}
close(new_sock);
return (void*)0;
}
int main(int argc,char* argv[])
{
if(argc!= 3){
usage(argv[0]);
return 1;
}
int listen_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock< 0)
{
perror("accept");
continue;
}
printf("accept succes!\n");
printf("get connect ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
//version 3
pthread_t id;
pthread_create(&id, NULL, request, (void*)new_sock);
pthread_detach(id);
}
return 0;
}
多进程与多线程服务器,使用telnet进行测试。