TCP实现局域网通信
TCP客户端通信步骤:
1:创建套接字 sockfd = socket(AF_INET ,SOCK_STREAM ,0);
2:填写服务器结构体信息
struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
其中服务器信息结构体要用sockaddr_in创建
3:发送客户端连接请求
connect(sockfd, (struct sockaddr *)&serveraddr,addrlen);
注意服务器信息结构体要进行强制类型转换
4:进行通信
recv(sockfd, buf1, 128, 0);
send(sockfd, buf, 128, 0);
注意send和recv可以设置阻塞和非阻塞 recv默认阻塞
其中可以通过创建进程和线程实现接收和发送
5:关闭套接字
TCP服务器通信步骤:
1:创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
2:将套接字和服务器信息结构体绑定
struct sockaddr_in serveraddr, clientaddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
bind(sockfd, (struct sockaddr *)&serveraddr, addrlen);
3:将套接字设置为监听状态
listen(sockfd, 5)
4:阻塞等待客户端连接请求
acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)
5:进行通信
6:关闭套接字
关闭监听套接字导致服务器无法建立新连接,但不影响已建立连接
关闭accept返回的套接字代表该套接字的连接关闭,不影响服务器监听
实现TCP并发服务器
客户端代码:client_Ancy.c
#include <stdio.h>
#include <errno.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h> //htons inet_addr
z
char buf1[128] = "";
pthread_t thread;
int sockfd;
char ip[] = "180.201.00.00";
char port[] = "8080";
void thread_do(){
while(1){
fgets(buf,128,stdin);
buf[strlen(buf) - 1] = '\0';
send(sockfd, buf, 128, 0);
}
}
int main(int argc, char const *argv[])
{
if (argc<3){
printf("Usage: %s [ip] [port]\n", argv[0]);
exit(1);
}
sockfd = socket(AF_INET ,SOCK_STREAM ,0);
struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//serveraddr.sin_addr.s_addr = inet_addr(ip);
//serveraddr.sin_port = htons(atoi(port));
connect(sockfd, (struct sockaddr *)&serveraddr,addrlen);
pthread_create(&thread, NULL, (void *)&thread_do,NULL);//此时可以通过把thread_do设置为指针函数,即定义时void * thread_do()参数可以写thread_do
while(1){
memset(buf1,0,128);
recv(sockfd, buf1, 128, 0);
printf("recv:%s\n",buf1);
}
close(sockfd);
}
多进程实现服务器代码:server_Ancy.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
//使用多进程实现TCP并发服务器
#define N 128
#define ERR_LOG(errmsg) do{\
perror(errmsg);\
exit(1);\
}while(0)
void handler(int sig)
{
wait(NULL);
}
int main(int argc, char const *argv[])
{
if(argc < 3)
{
fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
exit(1);
}
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
ERR_LOG("fail to socket");
}
//将套接字设置为允许重复使用本机地址或者为设置为端口复用
int on = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
ERR_LOG("fail to setsockopt");
}
//第二步:填充服务器网络信息结构体
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//第三步:将套接字与服务器网络信息结构体绑定
if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
{
ERR_LOG("fail to bind");
}
//第四步:将套接字设置为被动监听状态
if(listen(sockfd, 5) < 0)
{
ERR_LOG("fail to listen");
}
//使用型号,异步的方式处理僵尸进程
signal(SIGCHLD, handler);
while(1)
{
//第五步:阻塞等待客户端的连接请求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
ERR_LOG("fail to accept");
}
//打印客户端的信息
printf("%s -- %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
//使用fork函数创建子进程,父进程继续负责连接,子进程负责与客户端通信
pid_t pid;
if((pid = fork()) < 0)
{
ERR_LOG("fail to fork");
}
else if(pid > 0) //父进程负责执行accept,所以if语句结束后继续在accept函数的位置阻塞
{
}
else //子进程负责跟指定的客户端通信
{
char buf[N] = "";
ssize_t bytes;
while (1)
{
if((bytes = recv(acceptfd, buf, N, 0)) < 0)
{
ERR_LOG("fail to recv");
}
else if(bytes == 0)
{
printf("The client quited\n");
exit(0);
}
if(strncmp(buf, "quit", 4) == 0)
{
exit(0);
}
printf("from client: %s\n", buf);
strcat(buf, " ^_^");
if(send(acceptfd, buf, N, 0) < 0)
{
ERR_LOG("fail to send");
}
}
}
}
return 0;
}
多线程实现服务器代码:server_Ancy.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#define N 128
#define ERR_LOG(errmsg) do{\
perror(errmsg);\
exit(1);\
}while(0)
typedef struct{
struct sockaddr_in addr;
int acceptfd;
}MSG;
void *pthread_fun(void *arg)
{
char buf[N] = "";
ssize_t bytes;
MSG msg = *(MSG *)arg;
while (1)
{
if((bytes = recv(msg.acceptfd, buf, N, 0)) < 0)
{
ERR_LOG("fail to recv");
}
else if(bytes == 0)
{
printf("The client quited\n");
pthread_exit(NULL);
}
if(strncmp(buf, "quit", 4) == 0)
{
printf("The client quited\n");
pthread_exit(NULL);
}
printf("[%s - %d]: %s\n", inet_ntoa(msg.addr.sin_addr), ntohs(msg.addr.sin_port), buf);
strcat(buf, " ^_^");
if(send(msg.acceptfd, buf, N, 0) < 0)
{
ERR_LOG("fail to send");
}
}
}
int main(int argc, char const *argv[])
{
if(argc < 3)
{
fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
exit(1);
}
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
ERR_LOG("fail to socket");
}
//将套接字设置为允许重复使用本机地址或者为设置为端口复用
int on = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
ERR_LOG("fail to setsockopt");
}
//第二步:填充服务器网络信息结构体
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//第三步:将套接字与服务器网络信息结构体绑定
if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
{
ERR_LOG("fail to bind");
}
//第四步:将套接字设置为被动监听状态
if(listen(sockfd, 5) < 0)
{
ERR_LOG("fail to listen");
}
while(1)
{
//第五步:阻塞等待客户端的连接请求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
ERR_LOG("fail to accept");
}
//打印客户端的信息
//printf("%s -- %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
//创建子线程与客户端进行通信
MSG msg;
msg.addr = clientaddr;
msg.acceptfd = acceptfd;
pthread_t thread;
if(pthread_create(&thread, NULL, pthread_fun, &msg) != 0)
{
ERR_LOG("fail to pthread_create");
}
pthread_detach(thread);
}
return 0;
}