初识TCP/IP及使用套接字进行网络编程

时间:2021-10-17 10:19:17
通过对于TCP/IP协议以及套接字的学习,编写了最简单的客户端/服务器端程序:

1.单进程版本的服务器:

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>

int startup(char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port); //host to net
local.sin_addr.s_addr = inet_addr(ip); //
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(4);
}
return sock;
}
void Usage(char* proc)
{
printf("Usage:%s,[local ip],[ip_port]\n",proc);
}
int main(int argc,char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(1);
}

int listen_sock = startup(argv[1],atoi(argv[2]));
printf("fd:%d\n",listen_sock);
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("get a client:[%s][%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));

char buf[1024];
while(1)
{
ssize_t s = read(new_sock,buf,sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
printf("the client#: %s\n",buf);
write(new_sock,buf,sizeof(buf)-1);
}
else
{
if(s == 0)
{
printf("the client is quit\n");
break;
}
else
{
perror("read");
break;
}
}
}
close(new_sock);
}
close(listen_sock);
return 0;
}
2.多线程版本的server.c

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>
void* handler_request(void* arg)
{
int new_sock = (int)arg;
char buf[1024];
while(1)
{
ssize_t s = read(new_sock,buf,sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
printf("the client#: %s\n",buf);
write(new_sock,buf,sizeof(buf)-1);
}
else
{
if(s == 0)
{
printf("the client is quit\n");
break;
}
else
{
perror("read");
break;
}
}
}
close(new_sock);
}
int startup(char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port); //host to net
local.sin_addr.s_addr = inet_addr(ip); //
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(4);
}
return sock;
}
void Usage(char* proc)
{
printf("Usage:%s,[local ip],[ip_port]\n",proc);
}
int main(int argc,char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(1);
}

int listen_sock = startup(argv[1],atoi(argv[2]));
printf("fd:%d\n",listen_sock);
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("get a client:[%s][%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));

pthread_t tid;
pthread_create(&tid,NULL,handler_request,(void*)new_sock);
pthread_detach(tid);

}
close(listen_sock);
return 0;
}


3.client.c

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>

int main(int argc,char* argv[])
{

int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 2;
}

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);

if(connect(sock,(struct sockaddr*)&server,sizeof(server)) < 0)
{
perror("connect");
return 3;
}

while(1)
{
printf("Please Enter:");
fflush(stdout);
char buf[1024];
ssize_t s = read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1] = 0;
write(sock,buf,sizeof(buf)-1);
ssize_t s = read(sock,buf,sizeof(buf)-1);
printf("server# %s\n",buf);
}
else
{
perror("read");
break;
}
}

close(sock);
return 0;
}

4.多线程版本的运行结果:

初识TCP/IP及使用套接字进行网络编程

5.当服务器先于客户端断开时:需要及时启动服务器时,会发生server bind错误,启不起来:

初识TCP/IP及使用套接字进行网络编程

原因:

原因:TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,因为我们先Ctrl-C终止了server,server是主动关闭连接的一,TIME_WAIT期间仍然不能再次监听同样的server端 口。MSLRFC1122中规定为两分钟,但是各操作系统的实现不同,Linux上一般经过半分钟后 就可以再次启动server了。


注:由于作者水平有限,若有问题,请留言,谢谢!!