《TCP/IP网络编程》第2章 套接字类型与协议设置
#include <sys/socket.h>
//成功文件描述符,失败-1
int socket(int domain, int type, int protocol);
协议族(Protocal Family)
PF_INET,IPv4
PF_INET6,IPv6
PF_LOCAL,本地UNIX
PF_PACKET,底层套接字
PF_IPX,IPX Novell
套接字类型(Type)
套接字的数据传输方式。
- SOCK_STREAM,面向连接
数据不会消失,可靠;
按序传输,有序;
无数据边界(Boundary),基于字节,read()和write()并不一定一致(内部缓冲);
套接字一一对应。
int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- SOCK_DGRAM,面向消息
数据可能丢失或损毁,不可靠;
快速而非有序传输,无序高速;
有数据边界,read()和write()一致(一次传输一次接收);
限制每次传输数据大小;
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
TCP客户端
02.tcp_client_linux.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define IP "127.0.0.1"
#define PORT 9999
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char *argv[])
{
int sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1)
error_handling("socket() error");
socklen_t addr_size = sizeof(struct sockaddr_in);
struct sockaddr_in addr;
memset(&addr, 0, addr_size);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(IP);
addr.sin_port = htons(PORT);
if (connect(sock, (struct sockaddr *)&addr, addr_size) == -1)
error_handling("connect() error");
int read_len;
int str_len = 0;
char message[30];
for (int idx = 0; read_len = read(sock, &message[idx], 1); idx++)
{
if (read_len == -1)
error_handling("read() error");
str_len += read_len;
}
message[str_len] = '\0';
printf("Message from server: %s \n", message);
printf("Function read call count: %d \n", str_len);
close(sock);
return 0;
}
// gcc tcp_client.c -o tcp_client
// ./tcp_client
Windows平台
#include <winsock2.h>
//成功返回套接字句柄,失败INVALID_SOCKET
SOCKET socket(int af, int type, int protocol);
客户端
02.tcp_client_win.c
#include <stdio.h>
#include <winsock2.h>
#define IP "127.0.0.1"
#define PORT 9999
void ErrorHanding(const char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char *argv[])
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHanding("WSAStartup() error!");
SOCKET hSock = socket(PF_INET, SOCK_STREAM, 0);
if (hSock == INVALID_SOCKET)
ErrorHanding("socket() error!");
const int szAddr = sizeof(SOCKADDR_IN);
SOCKADDR_IN servAddr;
memset(&servAddr, 0, szAddr);
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(IP);
servAddr.sin_port = htons(PORT);
if (connect(hSock, (SOCKADDR *)&servAddr, szAddr) == SOCKET_ERROR)
ErrorHanding("connect() error!");
int strLen = 0;
int readLen;
char message[30];
int idx = 0;
for (; readLen = recv(hSock, &message[idx], 1, 0); idx++)
{
if (readLen == -1)
ErrorHanding("recv() error!");
strLen += readLen;
}
message[strLen] = '\0';
printf("Message from server: %s\n", message);
printf("Function recv call count: %d\n", idx);
closesocket(hSock);
WSACleanup();
return 0;
}
// gcc 02.tcp_client_win.c -o 02.tcp_client_win -lws2_32 && 02.tcp_client_win